A while ago I solved the FizzBuzz kata using Java 8 streams and lambdas. While the end result was functional, the intermediate steps were not. Surely I can do better.
As always, let’s start with a failing test:
Note that I start off on a functional course right away, using Java’s
I fake the implementation to make the test pass:
And refactor the test to remove duplication:
Then I add another test to generalize the implementation:
OK, pretty standard stuff so far. Next I need to replace 3 with “Fizz”:
Here I recognize that I need to apply one of two functions, depending on the input. This code works, but needs some cleaning up. First, as a stepping stone, I extract the lambdas into fields:
Next I emphasize that “3” and “Fizz” go together by extracting a class:
Here I’m using the standard Java
Predicate functional interface.
To add “Buzz”, I need to generalize the code from a single
if (hidden as the ternary operator) to a loop:
Oops, old habits… That should be a stream rather than a loop:
Much better. The next test is for multiples:
The last test is to combine Fizz and Buzz:
I generalized the single
Function into a
Functions, to which I apply the Map-Reduce pattern. I could have spelled out the Reduce part using something like
.reduce("", (a, b) -> a + b), but I think
Collectors.joining() is more expressive.
This doesn’t pass the test yet, since I return a stream of a single function. The fix is a little bit tricky, because I need to know whether any applicable replacer functions were found, and you can’t do that without terminating the stream. So I need to create a new stream using
And that’s it. The full code is on GitHub.
I learned two lessons from this little exercise:
- Java comes with a whole bunch of functional interfaces, like
Predicate, that are easily combined with streams to solve a variety of problems.
- The standard
if → whiletransformation becomes
if → streamin the functional world.