DEV Community

Stefano Fago
Stefano Fago

Posted on

The FizzBuzz: a branchless version with Java

Let dissect a Java program that implements the FizzBuzz problem with a branchless style, using a mix of bitwise operations, lambdas, and an optimized loop. Let's break it down step by step:


Overview of FizzBuzz Rules

  • Print numbers from 1 to 100.
  • If a number is divisible by 3, print "Fizz".
  • If a number is divisible by 5, print "Buzz".
  • If a number is divisible by both 3 and 5, print "FizzBuzz".
  • Otherwise, print the number itself.

Code Breakdown

1. Defining an Interface for Lambda Expressions

interface Provider {
    String value(int i);
}
Enter fullscreen mode Exit fullscreen mode
  • An interface Provider is needed since generic array are not possible, so Function or other functional interface are non allowed.
  • It has a single method value(int i), which will be implemented using lambda expressions.

2. Creating an Array of Provider Lambdas

Provider [] provider = {i->String.valueOf(i),i->"",i->""};
Enter fullscreen mode Exit fullscreen mode
  • This array holds three lambda expressions:
    • i -> String.valueOf(i): Returns the number as a string.
    • i -> "": Returns an empty string.
    • i -> "": Another empty string (used later for Fizz/Buzz handling).

3. Defining Text Segments

String [] textSegment = {"", "Fizz","FizzBuzz","Buzz"};
Enter fullscreen mode Exit fullscreen mode
  • This array maps to different text outputs:
    • textSegment[0] = "" (for numbers that aren't Fizz or Buzz)
    • textSegment[1] = "Fizz" (for numbers divisible by 3)
    • textSegment[2] = "FizzBuzz" (for numbers divisible by both 3 and 5)
    • textSegment[3] = "Buzz" (for numbers divisible by 5)

4. Using StringBuilder for Efficient String Concatenation

StringBuilder sb = new StringBuilder(3000);
String newline = System.lineSeparator();

Enter fullscreen mode Exit fullscreen mode
  • StringBuffer is used for efficient string concatenation.
  • newline stores the platform-specific line separator.

5. Main Loop with Bitwise Operations

for (int i = 1, a = 0, b = 0, providerIndex = 0, segmentIndex = 0; 
     i <= 100; 
     i++,
     a = ((528 >> i % 15 - 1) & 1) << 2,
     b = ((-2128340926 >> ((i % 15) << 1)) & 3) << 2,
     providerIndex = (b - a) >> 2,
     segmentIndex = (a + b) >> 2)
{
    sb.append(textSegment[segmentIndex])
      .append(provider[providerIndex].value(i))
      .append(newline);
}
Enter fullscreen mode Exit fullscreen mode

This loop iterates from i = 1 to 100 and performs the following calculations:

(1) Calculating a - 5 Multiples
a = ((528 >> i % 15 - 1) & 1) << 2
Enter fullscreen mode Exit fullscreen mode
  • 528 (binary: 100001000010000) is a bitmask that identifies numbers divisible by 5.
  • (i % 15 - 1) is used to shift the bitmask.
  • & 1 extracts whether the bit is set.
  • << 2 makes sure that if it's Fizz, a is 4, otherwise a is 0.
(2) Calculating b - 3 and 15 Multiples
b = ((-2128340926 >> ((i % 15) << 1)) & 3) << 2
Enter fullscreen mode Exit fullscreen mode
  • -2128340926 (binary: 100000010000001000000100000010) is a bitmask that identifies numbers divisible by 3 or 15.
  • ((i % 15) << 1) is used to shift the bitmask.
  • & 3 ensures only relevant bits are taken.
  • << 2 scales b properly.
(3) Determining providerIndex
providerIndex = (b - a) >> 2
Enter fullscreen mode Exit fullscreen mode
  • providerIndex determines whether to print the number (provider[0]) or an empty string (provider[1] or provider[2]) since provides the values: 0,1,2.
(4) Determining segmentIndex
segmentIndex = (a + b) >> 2
Enter fullscreen mode Exit fullscreen mode
  • segmentIndex selects the correct FizzBuzz text from textSegment since provides the values: 0,1,2,3.

6. Appending the Result

sb.append(textSegment[segmentIndex])
  .append(provider[providerIndex].value(i))
  .append(newline);
Enter fullscreen mode Exit fullscreen mode
  • The correct Fizz/Buzz text (textSegment[segmentIndex]) is added.
  • The number (or an empty string) is determined by provider[providerIndex].
  • A newline is appended.

7. Printing the Final Output

System.out.println(sb);
Enter fullscreen mode Exit fullscreen mode
  • The entire FizzBuzz output is printed at once.

Key Takeaways

  • Uses bitwise operations for efficient FizzBuzz checking.
  • Avoids multiple if-else conditions.
  • Optimizes string concatenation with StringBuilder.
  • Lambda functions simplify number/string selection.

There are more solutions about FizzBuzz, and maybe the code can be optimized further, but this code is funny and didactic enough to implement FizzBuzz in Java!

Heroku

Built for developers, by developers.

Whether you're building a simple prototype or a business-critical product, Heroku's fully-managed platform gives you the simplest path to delivering apps quickly — using the tools and languages you already love!

Learn More

Top comments (0)

AWS Q Developer image

Your AI Code Assistant

Implement features, document your code, or refactor your projects.
Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

👋 Kindness is contagious

If this article connected with you, consider tapping ❤️ or leaving a brief comment to share your thoughts!

Okay