Monday, May 8, 2023

How to solve FizzBuzz Problem in Java 8? Stream.map() Example

FizzBuzz is one of the most famous programming questions from interviews, which is generally used to weed out programmers who can't program. The problem is deceptively simple but you can't solve it if you don't know how to build programming logic. I love it just for its simplicity. Now coming back to the second part of this article, Java 8. It's been more than a year, I think it was March 18 last year when Java 8 was first released and to date, the most common question I have got is, how to learn new features of Java 8? like Optional, lambda expression, or Stream. I think the best way to learn Java 8 new features is the same as the best way to learn any new programming language like solving common coding problems, implementing data structure, common algorithms, and implementing famous design patterns.

I particularly find solving coding problems and an excellent way to learn and master Java 8 Streams. If you can solve problems like the Fibonacci series and a couple of others using lambda expressions and streams, you will progress quickly. Remember, Stream is a new way to write code without using for loop. Now coming back to our FizzBuzz problem, here is the problem statement and you need to solve it using Java 8.

Problem: For a given natural number greater than zero return:
  •     “Fizz” if the number is dividable by 3
  •     “Buzz” if the number is dividable by 5
  •     “FizzBuzz” if the number is dividable by 15
  •      Same number if the number is neither divisible by 3 nor 5.

Bonus points if you write unit tests to check your solution, you must do even if not asked during Interviews.

Btw, if you are not familiar with new Java 8 features like Effectively final variable then I suggest you first go through a comprehensive and up-to-date Java course like The Complete Java MasterClass on Udemy. It's also very affordable and you can buy in just $10 on Udemy sales which happen every now and then.




Solving FizzBuzz in Java 8 - Example

Here is the complete solution to the classic FizzBuzz problem using the new features of Java 8. There are three methods in this program, the first solution is the simplest way to solve FizzBuzz in Java without using any of Java 8 new features, but the second and third solution uses Java 8 features like lambda expressionOptional, and map() function and a new way of writing code.

The first solution is self-explanatory, we are checking if the number is divisible by 15, which means it is divisible by both 3 and 5, if yes we return FizzBuzz, otherwise, we check for divisibility by 3 and 5, if it's not divisible by any then we return the same number as String.

The second solution is interesting because it's written in Java 8. Optional is a new concept and class introduced in Java 8, mainly to deal with null in a better way and writing more expressive code which ensures that the coder doesn't forget to check the result of a method if it's Optional.

For the purpose of this program, we are using Optional as Stream, as you can treat it as Stream of either 1 or 0 elements. If Optional contains a value then it has one element otherwise it has zero elements. 

The map() function is written using a lambda expression, it goes to each element of  Optional and checks if it is divisible by 3, 5, or both and accordingly returns "Fizz", "Buzz" or "FizzBuzz". Let's understand this solution in little more detail :

public static String fizzBuzzInJava8(int number) {
        String result = Optional.of(number)
                .map(n -> (n % 3 == 0 ? "Fizz" : "") 
                             + (n % 5 == 0 ? "Buzz" : ""))
                .get();
        return result.isEmpty() ? Integer.toString(number) : result;
  }

 - The first line is creating Optional from the number we passed.
 - Second-line is actually equivalent to following code

public String map(int number){
   return  (n % 3 == 0 ? "Fizz" : "") + (n % 5 == 0 ? "Buzz" : "");
}

the map is usually used to convert one type to another, also known as transformation. You can now see the logic of checking divisibility by 3 and 5 and how it produces "FizzBuzz" if the number is divisible by both 3 and 5. If the number is not divisible by neither 3 or 5 then this method will return an empty String.
FizzBuzz Solution in Java 8 using Streams

The third line calls to get() method which returns the value if Optional contains any value otherwise it throws NoSuchElementException, Since we know that after map() method, Optional will either contain "Fizz", "Buzz", "FizzBuzz" or empty String, we are safe to call get() method here.

The last line in the method simply checks if the result is empty then it returns the original number as String otherwise results in itself.

Our second method is also applying the same logic but it's a little bit more expressive for Java programmers who are just started learning this new way of coding. In this method, the map method has exactly the same logic as our first method, but you see we have reduced a lot of boilerplate code related to method declaration using a lambda expression.

import java.util.Optional;

/**
 * FizzBuzz problem solution in Java 8. It's a classical problem to filter
 * programmers who can't program. Now you can use this to check whether your
 * Java candidate knows programming with Java 8 Streams or not.
 *
 * Problem : Write a method in Java which will return "Fizz" if the number is
 * dividable by 3 "Buzz" if the number is dividable by 5 "FizzBuzz" if the
 * number is dividable by 15 the same number if no other requirement is
 * fulfilled.
 *
 * @author Javin Paul
 */
public class FizzBuzzJava8 {

    public static void main(String args[]) {
        System.out.println("FizzBuzz using simple Java : " + fizzBuzz(3));
        System.out.println("FizzBuzz solution using Java 8  : " 
                                 + fizzBuzzInJava8(15));
    }

    /**
     * Simple Java solution of FizzBuzz Problem
     *
     * @param number
     * @return Fizz if number divisible by 3, Buzz if number divisible by 5
     * FizzBuzz if divisible by both 3 and 5, or else the same number
     */
    public static String fizzBuzz(int number) {
        if (number % 15 == 0) {
            return "FizzBuzz";
        } else if (number % 3 == 0) {
            return "Fizz";
        } else if (number % 5 == 0) {
            return "Buzz";
        }
        return Integer.toString(number);
    }

    /**
     * FizzBuzz Solution using Java 8 Optional, map and
     * Stream map() function is
     * really useful here.
     *
     * @param number
     * @return Fizz, Buzz, FizzBuzz or the number itself
     */
    public static String fizzBuzzInJava8(int number) {
        String result = Optional.of(number)
                .map(n -> (n % 3 == 0 ? "Fizz" : "") 
                               + (n % 5 == 0 ? "Buzz" : ""))
                .get();
        return result.isEmpty() ? Integer.toString(number) : result;
    }

    /*
     * Another Java 8 solution, this time its little bit more expressive
     * for Java 8 newbie.
     */
    public static String fizzBuzzSolutionJava8(int input) {
        return Optional.of(input)
                .map(i -> {
                    if (i % (3 * 5) == 0) {
                        return "FizzBuzz";
                    } else if (i % 3 == 0) {
                        return "Fizz";
                    } else if (i % 5 == 0) {
                        return "Buzz";
                    } else {
                        return Integer.toString(i);
                    }
                }).get();
    }

}




JUnit Test for FizzBuzz problem

Here is our set of JUnit tests to check all three solutions of Java 8. You can see we have in total 4 test cases, first to test with numbers which are only divisible by 3, second to test with a number which is divisible by 5, third to test with numbers which are divisible by both 3 and 5 e.g. 15, 30 or 45 and last one with numbers which are not divisible by either 3 or 5 e.g. 1 or 2. 

Together these four methods cover all the requirements of the FizzBuzz problem.

import org.junit.Assert;
import org.junit.Test;

/**
 * JUnit tests for our three FizzBuzz solution, including two in Java 8. 
 * @author WINDOWS 8
 */
public class FizzBuzzJava8Test {

    @Test
    public void testWithNumberIsDividableBy3() {
        Assert.assertEquals("Fizz", FizzBuzzJava8.fizzBuzz(3));
        Assert.assertEquals("Fizz", FizzBuzzJava8.fizzBuzzInJava8(3));
        Assert.assertEquals("Fizz", FizzBuzzJava8.fizzBuzzSolutionJava8(3));
    }

    @Test
    public void testWithNumberIsDividableBy5() {
        Assert.assertEquals("Buzz", FizzBuzzJava8.fizzBuzz(5));
        Assert.assertEquals("Buzz", FizzBuzzJava8.fizzBuzzInJava8(5));
        Assert.assertEquals("Buzz", FizzBuzzJava8.fizzBuzzSolutionJava8(5));
    }

    @Test
    public void testWithNumberIsDividableBy15() {
        Assert.assertEquals("FizzBuzz", FizzBuzzJava8.fizzBuzz(15));
        Assert.assertEquals("FizzBuzz", FizzBuzzJava8.fizzBuzzInJava8(15));
        Assert.assertEquals("FizzBuzz", FizzBuzzJava8.fizzBuzzSolutionJava8(15));
        Assert.assertEquals("FizzBuzz", FizzBuzzJava8.fizzBuzz(45));
        Assert.assertEquals("FizzBuzz", FizzBuzzJava8.fizzBuzzInJava8(45));
        Assert.assertEquals("FizzBuzz", FizzBuzzJava8.fizzBuzzSolutionJava8(45));
    }

    @Test
    public void testOtherNumbers() {
        Assert.assertEquals("1", FizzBuzzJava8.fizzBuzz(1));
        Assert.assertEquals("1", FizzBuzzJava8.fizzBuzzInJava8(1));
        Assert.assertEquals("1", FizzBuzzJava8.fizzBuzzSolutionJava8(1));
        Assert.assertEquals("7", FizzBuzzJava8.fizzBuzz(7));
        Assert.assertEquals("7", FizzBuzzJava8.fizzBuzzInJava8(7));
        Assert.assertEquals("7", FizzBuzzJava8.fizzBuzzSolutionJava8(7));
    }
}

and here is the result of our JUnit test. You can see all four test cases have passed, which means all three solutions are correct as per the specification of the fizzbuzz problem, don't you love the green bar?


How to solve FizzBuzz in Java 8 using lambda expression


This is Netbeans's JUnit run window, you can see it clearly saying all 4 tests are passed within 62 milliseconds.


That's all about how to solve FizzBuzz in Java 8. As I said solving simple programming problems or doing code katas are great ways to learn and master new features of Java 8, especially lambda expression and streams. FizzBuzz is one of the simplest of the problem but yet it teaches us how we can treat Optional as stream and use map function to transform each element of Optional.

In the coming weeks, we will also see some more examples of solving classic programming problems using Java 8 features. BTW,  If you are eager to do it by yourself, why not try to solve these 20 String algorithm problems using Java 8 Streams, lambdas, and other features.


If you like this tutorial and want to learn more about the new features of Java 8, you will love to check out these amazing articles :
  • Top 20 Date and Time Examples of Java 8 (examples)
  • What is the default method in Java 8. (tutorial)
  • Are you ready for Java 8 Certification? (read more)
  • How to use Map function in Java 8 (example)
  • 10 Examples of Stream API in Java (examples)
  • How to use Lambda Expression in Place of Anonymous class in Java 8 (solution)
  • 10 Java 7 Feature to revisit before you start with Java 8 (list)
  • 10 Best Tutorials to Learn Java 8 (list)
  • How to Read File in Java 8 in one line? (example)
  • How to filter List in Java 8 using Predicates? (solution)
  • What is the Effective final variable in Java 8? (answer)
  • Java 8 Comparator Example with Lambdas (example)
  • Java 8 tutorials and Books for FREE (resources)
  • How to sort objects by multiple fields in Java? (comparator example)

Thanks for reading this article so far. If you like this FizzBuzz solution in Java using map and function programming then please share them with your friends and colleagues. If you have any questions or feedback about this Java 8 tutorial then please drop a note.

P.S. -  If you want to learn more about Java Functional programming concepts like Lambda, Stream, and functional like map, flat map, and filter then please see these best Java Functional Programming courses. It explains key concepts like lambda expressions, streams, functional interface, Optionals, etc.   

4 comments :

Anonymous said...

Would be interesting to see the effects of object creation. I feel like the standard solution would be more efficient given a single input at a time

Anonymous said...

As a C/Java developer, I really hate java8 new features, beside the FuzzBuzz question is really easy(haven't heard too)!!! even my grandma would be accepted.
Java 8 new features were a really big disappointment.

Anonymous said...

That's a most stupid (mis)use of Optional I have ever seen.

TS said...

private static Func3 dividableMapping = (n, d, result) -> n % d == 0 ? result : "";
private static final List> FIZZ_BUZZ_FUNCTIONS = Arrays.asList(
n -> dividableMapping.call(n, 3, "Fizz"),
n -> dividableMapping.call(n, 5, "Buzz"));

public static String fizzBuzzInJava8(Integer n) {
String result = FIZZ_BUZZ_FUNCTIONS.stream().map(f -> f.call(n)).collect(Collectors.joining());
return result.isEmpty() ? String.valueOf(n) : result;
}

Post a Comment