Sitemap

Ternary, Predicate, and Pattern Matching for FizzBuzz with Java 26

5 min readJun 12, 2026

--

Exploring FizzBuzz solutions from Java 8 to Java 26

Press enter or click to view image in full size
Photo by James Wainscoat on Unsplash

Ten Years of FizzBuzz using JDK 8 Lambda

Ten years ago, someone asked a question about implementing FizzBuzz using JDK 8 Lambdas.

There was a final request in the question.

Can anyone try to use predicate instead ? I could not think of a way to do this.

I provided two basic answers, and later added some updates. The first answer used a ternary expression as a Function. It is the most concise answer. The second answer used a CaseFunction from Eclipse Collections. A CaseFunction acts like an object-oriented switch expression. You can use the addCase method to add as many Predicate and Function combinations as you want. The constructor takes the default Function to apply in the case where there are no Predicate matches.

My answer was accepted by the OP.

This question was asked and answered two years after Java 8 was released, and six months after Eclipse Collections was forked from GS Collections.

Now we have Java 26 with support for primitive Pattern Matching with Switch.

Fizzing and Buzzing with Java 26

When I answered the question ten years ago, I was hoping there would be some way to express this problem with a switch statement as an expression. Here we are today, 18 major Java versions later, and we can now express this problem using a primitive switch expression. Woo hoo!

I will show step by step how we can create the Function objects using ternary expression, CaseFunction, and primitive Pattern Matching with Switch. Instead of outputting just “Fizz”, “Buzz”, or “FizzBuzz”, I will output “🥤”, “🐝”, and “🥤🐝”. This will make the tests and code more concise and fun to read.

The Expected String

The following EXPECTED String will be used to test the results of each approach.

private static final String EXPECTED =
"🥤🐝, 1, 2, 🥤, 4, 🐝, 🥤, 7, 8, 🥤, 🐝, 11, 🥤, 13, 14, 🥤🐝, 16, 17, 🥤, 19, 🐝";

A Tale of Two Intervals

Eclipse Collections has an Interval class and an IntInterval class. Interval is a LazyIterable<Integer> and a List<Integer>. Interval boxes the int values in its range as Integer objects. IntInterval is an ImmutableIntList, and does not box int values as Integer.

private static final Interval INTERVAL = Interval.zeroTo(20);
private static final IntInterval INT_INTERVAL = IntInterval.zeroTo(20);

Ternary Expression

The ternary expression tests for a value being divisible by 3 and/or 5. If it’s divisible by both, it returns “🥤🐝”. If it’s divisible by 3 only, it returns “🥤”. If it’s divisible by 5, it returns “🐝”. Otherwise it returns the value.

private static final IntToObjectFunction<String> FIZZ_BUZZ_TERNARY =
i -> i % 3 == 0 ?
(i % 5 == 0 ? "🥤🐝" : "🥤") :
(i % 5 == 0 ? "🐝" : Integer.toString(i));

CaseFunction

The CaseFunction is slightly more verbose, but it is easier to read. This is because each Predicate passed into addCase is a single test. The code optimizes for the divisible by 3 and 5 case by just checking if it is divisible by 15.

private static final CaseFunction<Integer, Object> FIZZ_BUZZ_FUNCTION_OBJ =
new CaseFunction<Integer, Object>(Object::toString)
.addCase(i -> i % 15 == 0, e -> "🥤🐝")
.addCase(i -> i % 3 == 0, e -> "🥤")
.addCase(i -> i % 5 == 0, e -> "🐝");

IntCaseFunction

The IntCaseFunction was added to Eclipse Collections after primitive collections were added. IntCaseFunction does not require boxing the int values in a primitive collection to boxed Integer values. Otherwise, it looks very much like CaseFunction.

private static final IntCaseFunction<String> FIZZ_BUZZ_FUNCTION =
new IntCaseFunction<>(Integer::toString)
.addCase(i -> i % 15 == 0, e -> "🥤🐝")
.addCase(i -> i % 3 == 0, e -> "🥤")
.addCase(i -> i % 5 == 0, e -> "🐝");

Primitive Pattern Matching with Switch

In Java 26, we can now use the primitive Pattern Matching for Switch with the when clause. I have been waiting for ten years to be able to write this code, and now I can. Progress happens, slowly sometimes, but it happens.

private static final IntToObjectFunction<String> FIZZ_BUZZ_SWITCH_CASE =
each -> switch (each)
{
case int i when i % 15 == 0 -> "🥤🐝";
case int i when i % 3 == 0 -> "🥤";
case int i when i % 5 == 0 -> "🐝";
default -> Integer.toString(each);
};

The Tests

The following shows the tests using Interval and IntInterval with the various forms of FizzBuzz expressions as Function types.

@Test
void intIntervalTernary()
{
String fizzBuzzString =
INT_INTERVAL.collect(FIZZ_BUZZ_TERNARY).makeString();

assertEquals(EXPECTED, fizzBuzzString);
}

@Test
void intIntervalIntCaseFunction()
{
String fizzBuzzString =
INT_INTERVAL.collect(FIZZ_BUZZ_FUNCTION).makeString();

assertEquals(EXPECTED, fizzBuzzString);
}

@Test
void intIntervalSwitchCase()
{
String fizzBuzzString =
INT_INTERVAL.collect(FIZZ_BUZZ_SWITCH_CASE).makeString();

assertEquals(EXPECTED, fizzBuzzString);
}

@Test
void intervalCaseFunction()
{
String fizzBuzzString =
INTERVAL.collect(FIZZ_BUZZ_FUNCTION_OBJ).makeString();

assertEquals(EXPECTED, fizzBuzzString);
}

@Test
void intervalCaseFunctionMakeString()
{
String fizzBuzzString =
INTERVAL.makeString(FIZZ_BUZZ_FUNCTION_OBJ, "", ", ", "");

assertEquals(EXPECTED, fizzBuzzString);
}

All of the examples, except the last one, use collect followed by makeString to create the String result. The last example uses an overload of makeString which takes a Function along with the start, separator, and end String parameters.

IntStream Example

We can use the same primitive Pattern Matching with Switch expression (FIZZ_BUZZ_SWITCH_CASE) with IntStream. The major difference (other than API) between IntStream and IntInterval is that an IntStream can only be used once. I can’t store it in a static variable and reuse it for different tests.

@Test
void intStreamSwitchCase()
{
String fizzBuzzString =
IntStream.rangeClosed(0, 20)
.mapToObj(FIZZ_BUZZ_SWITCH_CASE)
.collect(Collectors.joining(", "));

assertEquals(EXPECTED, fizzBuzzString);
}

Final Thoughts

It’s nice to see Java continue to evolve with new language features. Some of the new features work well with both Eclipse Collections and Java Stream. Many folks will have to wait until Java 29 to use this new feature, unless they are comfortable enabling preview features with Java 25.

Thanks for reading!

I am the creator of and committer for the Eclipse Collections OSS project, which is managed at the Eclipse Foundation. Eclipse Collections is open for contributions. I am the author of the book, Eclipse Collections Categorically: Level up your programming game.

--

--

Donald Raab
Donald Raab

Written by Donald Raab

Java Champion. Creator of the Eclipse Collections OSS Java library (https://github.com/eclipse-collections). Inspired by Smalltalk. Opinions are my own.