Back to Miscellaneous Coding
Q10Question 10 of 52

FizzBuzz

Key Concepts
  • FizzBuzz tests control flow, the modulo operator, and the ordering of overlapping conditions
  • A number divisible by both 3 and 5 is divisible by 15; the combined case must be checked first in an if-else chain
  • The append approach builds the output string by appending Fizz and Buzz independently, naturally handling the combined case
  • The append approach is extensible: adding a new rule requires only one more append line without touching existing logic
  • Edge cases include N of zero or negative, and the all-zeros input where the result is just the numbers
  • FizzBuzz is not about difficulty; it reveals whether a candidate writes clean, correct, maintainable code

Definition

Print the number, but say Fizz for multiples of three, Buzz for multiples of five, and FizzBuzz for multiples of both.
  • FizzBuzz – a classic programming exercise that tests control flow and the modulo operator.
  • Modulo (%) – gives the remainder of a division; i % 3 == 0 means i is a multiple of three.
  • Condition ordering – the combined FizzBuzz case (divisible by 15) must be checked before the individual Fizz or Buzz cases in an if-else chain.
  • Append approach – builds the output by appending Fizz if divisible by 3, then Buzz if divisible by 5, producing FizzBuzz naturally without a special 15 check.
  • Extensibility – the append approach scales to additional rules (e.g., Bazz for 7) by adding one line.

Imagine the National Bank of India tags a sequence of transaction slips for a reconciliation drill. Every third slip gets a Fizz sticker for compliance review, every fifth slip gets a Buzz sticker for audit review, and a slip that is both third and fifth gets both stickers reading FizzBuzz. Every other slip keeps its number. The clerk must check the both-stickers case first in an if-else chain, or she would wrongly stop at just one sticker.

Understanding the Concepts

What is FizzBuzz?

FizzBuzz is a classic programming exercise. You print the numbers from 1 to N, but replace multiples of 3 with Fizz, multiples of 5 with Buzz, and multiples of both 3 and 5 with FizzBuzz. It tests control flow, the modulo operator, and the critical ordering of overlapping conditions.

At the National Bank of India, Rajesh uses this as a warm-up exercise to demonstrate clean condition handling before writing more complex compliance rule engines.

JAVA
package com.bank.drill;

public class FizzBuzzDemo {
    public static void main(String[] args) {
        int n = 20;
        for (int i = 1; i <= n; i++) {
            System.out.println(fizzBuzz(i));
        }
    }

    static String fizzBuzz(int i) {
        if (i % 15 == 0) return "FizzBuzz";
        if (i % 3 == 0) return "Fizz";
        if (i % 5 == 0) return "Buzz";
        return String.valueOf(i);
    }
}
TEXT
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz

Why does condition ordering matter?

If you check i % 3 == 0 first in an if-else chain, you return Fizz for 15 and never reach the combined case. The number 15 is divisible by both 3 and 5, so it should print FizzBuzz. The most specific case must be checked first.

JAVA
// WRONG: checks 3 first, misses FizzBuzz
static String fizzBuzzWrong(int i) {
    if (i % 3 == 0) return "Fizz";       // 15 hits here!
    if (i % 5 == 0) return "Buzz";
    if (i % 15 == 0) return "FizzBuzz";  // never reached for 15
    return String.valueOf(i);
}

// CORRECT: checks 15 (most specific) first
static String fizzBuzzCorrect(int i) {
    if (i % 15 == 0) return "FizzBuzz";  // 15 hits here correctly
    if (i % 3 == 0) return "Fizz";
    if (i % 5 == 0) return "Buzz";
    return String.valueOf(i);
}
TEXT
fizzBuzzWrong(15)   -> "Fizz"      // WRONG
fizzBuzzCorrect(15) -> "FizzBuzz"  // CORRECT

How does the append approach work?

Instead of an if-else chain, build a string by appending. Append Fizz if divisible by 3, append Buzz if divisible by 5. If nothing was appended, use the number itself. This naturally produces FizzBuzz for 15 without a special case and is more extensible.

JAVA
package com.bank.drill;

public class FizzBuzzAppend {

    static String fizzBuzz(int i) {
        StringBuilder sb = new StringBuilder();
        if (i % 3 == 0) sb.append("Fizz");
        if (i % 5 == 0) sb.append("Buzz");
        return sb.length() == 0 ? String.valueOf(i) : sb.toString();
    }

    public static void main(String[] args) {
        for (int i = 1; i <= 15; i++) {
            System.out.println(i + " -> " + fizzBuzz(i));
        }
    }
}
TEXT
1 -> 1
2 -> 2
3 -> Fizz
4 -> 4
5 -> Buzz
6 -> Fizz
7 -> 7
8 -> 8
9 -> Fizz
10 -> Buzz
11 -> 11
12 -> Fizz
13 -> 13
14 -> 14
15 -> FizzBuzz

How is the append approach more extensible?

If the compliance team adds a rule for every seventh transaction to get a Bazz tag, the append approach needs only one more line. The if-else approach would need to handle 3-and-7, 5-and-7, 3-and-5-and-7, and every other combination, which becomes a combinatorial explosion.

JAVA
package com.bank.drill;

public class FizzBuzzBazz {

    static String fizzBuzzBazz(int i) {
        StringBuilder sb = new StringBuilder();
        if (i % 3 == 0) sb.append("Fizz");
        if (i % 5 == 0) sb.append("Buzz");
        if (i % 7 == 0) sb.append("Bazz");
        return sb.length() == 0 ? String.valueOf(i) : sb.toString();
    }

    public static void main(String[] args) {
        System.out.println(fizzBuzzBazz(21));   // 21 = 3*7
        System.out.println(fizzBuzzBazz(35));   // 35 = 5*7
        System.out.println(fizzBuzzBazz(105));  // 105 = 3*5*7
    }
}
TEXT
FizzBazz
BuzzBazz
FizzBuzzBazz

How do you use Java Streams for FizzBuzz?

A functional approach uses IntStream and map to produce the output. This is concise but may be less readable for beginners.

JAVA
package com.bank.drill;

import java.util.stream.IntStream;

public class FizzBuzzStream {
    public static void main(String[] args) {
        IntStream.rangeClosed(1, 15)
            .mapToObj(i -> {
                StringBuilder sb = new StringBuilder();
                if (i % 3 == 0) sb.append("Fizz");
                if (i % 5 == 0) sb.append("Buzz");
                return sb.length() == 0 ? String.valueOf(i) : sb.toString();
            })
            .forEach(System.out::println);
    }
}

What are the edge cases?

Edge cases include N of zero (print nothing), N of one (just print 1), and negative N (print nothing or handle gracefully). Another edge case is very large N where you should use a StringBuilder to collect output instead of creating many String objects.

JAVA
package com.bank.drill;

public class FizzBuzzEdgeCases {
    public static void main(String[] args) {
        // Edge case 1: N = 0
        System.out.println("N=0:");
        for (int i = 1; i <= 0; i++) {
            System.out.println(fizzBuzz(i));  // prints nothing
        }

        // Edge case 2: N = 1
        System.out.println("N=1:");
        for (int i = 1; i <= 1; i++) {
            System.out.println(fizzBuzz(i));
        }

        // Edge case 3: negative N
        System.out.println("N=-5:");
        for (int i = 1; i <= -5; i++) {
            System.out.println(fizzBuzz(i));  // prints nothing
        }
    }

    static String fizzBuzz(int i) {
        StringBuilder sb = new StringBuilder();
        if (i % 3 == 0) sb.append("Fizz");
        if (i % 5 == 0) sb.append("Buzz");
        return sb.length() == 0 ? String.valueOf(i) : sb.toString();
    }
}
TEXT
N=0:
N=1:
1
N=-5:

How does this relate to real banking rule engines?

FizzBuzz demonstrates the same pattern used in banking rule engines where multiple overlapping conditions must be evaluated and combined. In a compliance system, a transaction might match both a fraud rule and an AML rule, and both tags must be applied, not just the first match.

JAVA
package com.bank.compliance;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

public class TransactionTagger {

    public List<String> tagTransaction(BigDecimal amount, String country) {
        List<String> tags = new ArrayList<>();

        if (amount.compareTo(new BigDecimal("1000000")) > 0) {
            tags.add("HIGH_VALUE");
        }
        if (isHighRiskCountry(country)) {
            tags.add("HIGH_RISK_COUNTRY");
        }
        if (amount.compareTo(new BigDecimal("5000000")) > 0
                && isHighRiskCountry(country)) {
            tags.add("ESCALATE_TO_COMPLIANCE_HEAD");
        }

        return tags.isEmpty()
            ? List.of("STANDARD")
            : tags;
    }

    private boolean isHighRiskCountry(String country) {
        return List.of("XX", "YY").contains(country);
    }
}

What are common mistakes?

The most common mistake is checking divisibility by 3 before divisibility by 15, which makes the combined case unreachable. Another mistake is using == on strings instead of .equals() when comparing the output.

JAVA
// WRONG: if-else chain checks 3 before 15
if (i % 3 == 0) {
    result = "Fizz";
} else if (i % 5 == 0) {
    result = "Buzz";
} else if (i % 15 == 0) {  // dead code: 15 already caught by % 3
    result = "FizzBuzz";
}

// CORRECT: use the append approach to avoid the ordering trap entirely
StringBuilder sb = new StringBuilder();
if (i % 3 == 0) sb.append("Fizz");
if (i % 5 == 0) sb.append("Buzz");
String result = sb.length() == 0 ? String.valueOf(i) : sb.toString();

What should a senior engineer know?

  • FizzBuzz as a filter. It quickly reveals whether a candidate writes clean, correct, maintainable code. The difficulty is not the point; the craftsmanship is.
  • Composition over branching. The append approach demonstrates building results by composing independent checks rather than creating a branching tangle.
  • Generalization. The same pattern applies to any system where multiple overlapping rules produce tags, labels, or actions that must be combined.
  • Performance. For very large N, avoid creating a new StringBuilder per iteration. Reuse it by clearing with sb.setLength(0) inside the loop.

Visual Overview

DIAGRAM
  Input: i = 15

  if-else approach (MUST check 15 first):
  ┌─────────────────┐
  │ i % 15 == 0 ?   │── Yes ──> "FizzBuzz"
  └─────────────────┘
         │ No
  ┌─────────────────┐
  │ i % 3 == 0 ?    │── Yes ──> "Fizz"
  └─────────────────┘
         │ No
  ┌─────────────────┐
  │ i % 5 == 0 ?    │── Yes ──> "Buzz"
  └─────────────────┘
         │ No
       String.valueOf(i)

  Append approach (no ordering trap):
  ┌──────────────┐
  │ sb = ""      │
  └──────────────┘
         │
  ┌──────────────┐
  │ i % 3 == 0 ? │── Yes ──> sb += "Fizz"   sb = "Fizz"
  └──────────────┘
         │
  ┌──────────────┐
  │ i % 5 == 0 ? │── Yes ──> sb += "Buzz"   sb = "FizzBuzz"
  └──────────────┘
         │
  sb.isEmpty() ? String.valueOf(i) : sb  ──> "FizzBuzz"

Key Takeaway

FizzBuzz asks you to print the numbers from 1 to N, replacing multiples of 3 with Fizz, multiples of 5 with Buzz, and multiples of both with FizzBuzz. The core tool is the modulo operator, which gives the remainder of a division, and the trap the exercise is designed to catch is the ordering of conditions in an if-else chain.

If you check divisibility by 3 first, you return Fizz for 15 and never reach the combined case. The fix is to check 15 first, but the cleaner solution is the append approach: append Fizz if divisible by 3, append Buzz if divisible by 5, and if nothing was appended use the number. This naturally produces FizzBuzz for 15 without any special case.

The real value of the append approach is extensibility. When the compliance team at the National Bank of India adds a new rule for every seventh transaction, I add one line without touching the existing logic. The if-else approach would need to handle every combination of 3, 5, and 7, which becomes a combinatorial explosion.

The senior-level insight is that FizzBuzz is not about difficulty. It reveals whether a candidate writes clean, correct, maintainable code and handles edge cases gracefully. The two real lessons, composing overlapping rules by appending rather than branching and testing the most specific condition first, generalize directly to real rule engines in banking where multiple conditions must be evaluated and combined.

Remember one sentence: append Fizz for 3 and Buzz for 5 independently, and the combined case handles itself without a special 15 check.

---

Share
Use ← → arrow keys to navigate