FizzBuzz in Java

beginner·  Control Flow  ·  Loops

Problem

FizzBuzz is a classic warm-up exercise built around checking divisibility with the modulo operator.

Print the numbers 1 through 30, replacing multiples of 3 with 'Fizz', multiples of 5 with 'Buzz', and multiples of both with 'FizzBuzz'.

Input
1–30
Output
1, 2, Fizz, 4, Buzz, ...

Java Program

Java
public class FizzBuzz { public static void main(String[] args) { for (int i = 1; i <= 30; i++) { // Check the combined case first so multiples of both aren't caught by % 3 or % 5 alone if (i % 15 == 0) System.out.println("FizzBuzz"); else if (i % 3 == 0) System.out.println("Fizz"); else if (i % 5 == 0) System.out.println("Buzz"); else System.out.println(i); } } }

Output

1 2 Fizz 4 Buzz Fizz 7 ... FizzBuzz

Core Logic

The modulo operator does all the heavy lifting here — check divisibility by 15 first, then fall back to 3 and 5.

How It Works
  1. 1A for loop counts i from 1 to 30.
  2. 2i % 15 == 0 is checked first — 15 is 3 × 5, so this catches numbers divisible by both before the individual checks run.
  3. 3i % 3 == 0 catches remaining multiples of 3 and prints "Fizz".
  4. 4i % 5 == 0 catches remaining multiples of 5 and prints "Buzz".
  5. 5Anything left over is just printed as the number itself.
At i = 15, the % 15 check fires first, printing "FizzBuzz" instead of falling through to the % 3 or % 5 branches.
💡

Key Point: Ordering the % 15 check before % 3 and % 5 is what prevents 'FizzBuzz' from being printed as just 'Fizz'.

Complexity
Time Complexity: O(n)Space Complexity: O(1)

Why: Each number from 1 to n is visited exactly once, and only the loop counter and constant strings are held at any point.

Key Concepts

for loopmodulo operatorif / else if

Approach 2: StringBuilder (Independent Conditions)

Java
public class FizzBuzzStringBuilder { public static void main(String[] args) { for (int i = 1; i <= 30; i++) { StringBuilder output = new StringBuilder(); if (i % 3 == 0) output.append("Fizz"); // independent check for 3 if (i % 5 == 0) output.append("Buzz"); // independent check for 5 // If neither condition matched, fall back to printing the number System.out.println(output.length() > 0 ? output.toString() : String.valueOf(i)); } } }

Output

1 2 Fizz 4 Buzz Fizz 7 ... FizzBuzz

Core Logic

Instead of special-casing 'divisible by both', let 'Fizz' and 'Buzz' get appended independently — the combination takes care of itself.

How It Works
  1. 1An empty StringBuilder is created fresh for every number.
  2. 2if (i % 3 == 0) appends "Fizz" — independently of whether 5 also divides i.
  3. 3if (i % 5 == 0) appends "Buzz" in the same way, so a multiple of both ends up with "FizzBuzz" naturally.
  4. 4If neither condition added anything, output.length() > 0 is false, so the number itself is printed instead.
At i = 15, both if blocks run, appending "Fizz" then "Buzz", so output becomes "FizzBuzz" without a dedicated % 15 check.
💡

Key Point: This scales better if more rules were added later (like '% 7 → Bazz') — each rule is an independent if, instead of needing a new combined-case branch for every pair of rules.

Complexity
Time Complexity: O(n)Space Complexity: O(1)

Why: A fresh, small StringBuilder is created and discarded each iteration, so its size never grows with n.

Key Concepts

StringBuilderindependent conditionsfor loop

Approach 3: Java 8

Java
import java.util.stream.IntStream; public class FizzBuzzStream { public static void main(String[] args) { IntStream.rangeClosed(1, 30) // Same % 15 → % 3 → % 5 ordering as the loop version, as a ternary chain .mapToObj(i -> i % 15 == 0 ? "FizzBuzz" : i % 3 == 0 ? "Fizz" : i % 5 == 0 ? "Buzz" : String.valueOf(i)) .forEach(System.out::println); } }

Output

1 2 Fizz 4 Buzz Fizz 7 ... FizzBuzz

Core Logic

The same 1-to-30 sweep can be expressed as a stream pipeline — map each number to its FizzBuzz string, then print the whole stream.

How It Works
  1. 1IntStream.rangeClosed(1, 30) produces the numbers 1 through 30 as a stream, replacing the for loop's counter.
  2. 2.mapToObj(i -> ...) turns each int into the right String, using the same % 15, % 3, and % 5 checks as a ternary chain instead of if/else if.
  3. 3.forEach(System.out::println) prints each mapped string in order, using a method reference instead of a lambda body.
Mapping 15 checks 15 % 15 == 0 first, producing "FizzBuzz", the same as the loop version's combined check.
💡

Key Point: The ternary chain inside mapToObj() has to preserve the same '% 15 before % 3 or % 5' ordering as the loop version — streams don't change the underlying logic, just how it's expressed.

Complexity
Time Complexity: O(n)Space Complexity: O(1)

Why: mapToObj() and forEach() process and print one number at a time without ever materializing the full sequence into a collection.

Key Concepts

StreamIntStream.rangeClosed()mapToObj()

Interview Questions

Why must divisibility by 15 be checked first?

A number like 30 is divisible by 3, 5 and 15. If the check for 3 came first, it would print "Fizz" and never reach "FizzBuzz". Testing the most specific condition first prevents that.

Can FizzBuzz be written without checking 15 at all?

Yes. Build the output in a StringBuilder: append "Fizz" if divisible by 3, append "Buzz" if divisible by 5, and print the number only if nothing was appended. That version also extends easily to extra rules such as "Bazz" for 7.

Why is FizzBuzz such a common interview question?

It's small enough to write in a few minutes but quickly shows whether a candidate understands loops, the modulo operator and the order of conditions.

Learn the Concept

Related Programs