Skip to content
Ameen Abozaid
PublishedBEG-012-L03

Classic switch and fall-through

  • Lesson 3 of 6
  • 10 min read
  • Beginner
On This Lesson 11 topics

Lesson Overview

An else if chain is perfect for ranges such as "80 and above". But many decisions are not about ranges. They pick one choice out of a fixed list: day 1 to 7, a menu option, a command word, a month number. You could write such a list as a long chain of if (day == 1) ... else if (day == 2) ..., but Java offers a tool built for it, the switch statement.

The classic form of switch has one famous trap, fall-through: if you forget a small keyword, the program runs more code than you meant. Understanding fall-through is useful twice: it explains a very common bug, and it explains why the modern form in the next lesson was invented. Think of a junction where the sign sends you to a roundabout exit, but without a barrier you keep driving into the next exit too.

This lesson builds on Lessons 1 and 2 (conditions and chains) and on Module 9 (int, char, and String). Lesson 4 shows the arrow form, which removes the trap.

Learning Objectives

By the end of this lesson you will be able to:

  • Write a classic switch statement with case labels, break, and default.
  • Predict the output of a switch in which a break is missing (fall-through).
  • Group several labels onto one action on purpose.
  • Name the types a switch can use and explain why ranges do not fit.
  • Decide whether a given decision is better written as a switch or an if chain.
  • Read the compiler messages for duplicate labels and for a selector type that is not allowed.

Written Explanation

The shape of a switch

java
switch (day) {
    case 6:
    case 7:
        System.out.println("Weekend");
        break;
    default:
        System.out.println("Weekday");
}

Read it like this. Java evaluates the expression in the parentheses once, the selector. It looks for the first case label whose constant equals the selector, and starts running statements from that label. It keeps running until it reaches a break or the closing brace. If no label matches, it jumps to default, if there is one; if there is none, the whole switch does nothing.

Each case must be a constant (a literal such as 6 or "stop", or a final constant), not a variable and not a test. Two labels with the same value are a compile error.

What a switch can look at

The Java Language Specification lists the selector types allowed in the classic form that this lesson uses: char, byte, short, int, their wrapper classes, String, and enum types (which you will meet later). A long, float, double, or boolean selector is rejected.

A switch only compares for equality. There is no way to write "greater than 80" in a case label, so ranges belong to if chains. When the selector is a String, the text is compared by content, so "stop" matches "stop". (Why that is not the same as == on strings is explained in a later module.) Be careful with letter case: "Stop" does not match the label "stop".

break and fall-through

The break statement ends the switch and continues after the closing brace. It is the barrier at the exit. If you omit it, Java does not stop at the next case label: labels are only entry points, not walls, so execution falls through into the following statements, whatever label they carry. Fall-through is how the language is defined for the classic case X: form; it is not a bug in Java.

Sometimes you want it, as in the weekend example: label 6 has no statements and no break, so it falls into label 7's block. Several labels share one action. That is intentional fall-through, and it is the only kind worth writing. Everywhere else, end each group with break.

default

default catches every value that matches no label. It can appear anywhere in the switch, but by convention it is last, and then it does not need a break. Include it almost always: it is the classic else, the place where you handle values you did not expect (a month number 13, an unknown command).

Switch or if?

SituationBetter tool
One value compared with several fixed constantsswitch
Ranges ("at least 80") or comparisonsif / else if
Two or more variables in the testif with && or or logic
Only two outcomesif / else

Examples

Example 1: weekend or weekday (simple)

java
int day = 6;
switch (day) {
    case 6:
    case 7:
        System.out.println("Weekend");
        break;
    default:
        System.out.println("Weekday");
}

Output:

text
Weekend

Label 6 matches, there is nothing to run there, so execution slides into label 7's println, then break leaves the switch. Any other value goes to default. (Whether days 6 and 7 are the weekend depends on the country and on how you number the days; here it is simply a rule we chose.)

Example 2: days in a month and a command word (practical)

java
int m = 4;
int days;
switch (m) {
    case 4: case 6: case 9: case 11:
        days = 30;
        break;
    case 2:
        days = 28;
        break;
    default:
        days = 31;
}
System.out.println("Month " + m + " has " + days + " days");

Output:

text
Month 4 has 30 days

Four labels share one action, and February is handled alone (ignoring leap years for now). Because every path, including default, assigns days, the compiler accepts the later use of days.

A String selector works the same way:

java
String cmd = "stop";
switch (cmd) {
    case "go":
        System.out.println("Starting");
        break;
    case "stop":
        System.out.println("Stopping");
        break;
    default:
        System.out.println("Unknown command");
}

Output: Stopping.

Example 3: the missing break (realistic)

A menu program prints what each option does. The author forgets two break statements:

java
int option = 2;
switch (option) {
    case 1:
        System.out.println("Open");
    case 2:
        System.out.println("Save");
    case 3:
        System.out.println("Exit");
        break;
    default:
        System.out.println("Unknown");
}

Real output:

text
Save
Exit

The user chose option 2, "Save", and the program also exited. Execution entered at label 2, found no break, and fell into label 3. With a break after Save, only Save would print.

Fall-through is sometimes used deliberately for cumulative rules:

java
int level = 3;
switch (level) {
    case 3:
        System.out.println("admin rights");
    case 2:
        System.out.println("edit rights");
    case 1:
        System.out.println("read rights");
}

Output: admin rights, edit rights, read rights on three lines. It works, but a reader cannot tell it from a forgotten break, so if you ever write it, add a comment saying it is intentional.

Backend Insight

Backends are full of "dispatch on a code" decisions: an HTTP method (GET, POST, DELETE), an order status (NEW, PAID, SHIPPED), a message type, a command from a queue. These are exact-match choices over a small fixed set, which is the sweet spot of switch.

The missing-break bug is dangerous there for a specific reason: it does not crash. A PAID order that falls into the SHIPPED code may trigger a shipment for something not yet ready, and the program carries on as if everything were fine. Many teams therefore prefer the arrow form (next lesson) and enable compiler or IDE warnings for fall-through. If you must use the classic form, review every case for its break the way you review a boundary: it is the line that is easy to miss and costly when missing.

Also keep a default that does something loud when it sees a value nobody planned for, such as printing an error. A silent default hides bad data.

Common Mistakes

Mistake 1: Forgetting break

  • Incorrect: a case block with no break and no comment.
  • Correct: end every group with break, or mark intentional fall-through.

See Example 3. If more lines print than you expect, check the cases above the one you chose.

Mistake 2: Trying to use a range or condition in a case

  • Incorrect: case score >= 80:
  • Correct: use an else if chain, or compute a small whole number first (such as score / 10).

The compiler's actual message for the incorrect line:

text
L03c.java:14: error: incompatible types: boolean cannot be converted to int
            case score >= 80: System.out.println("B"); break;
                       ^

Mistake 3: Duplicate labels or a selector type that is not allowed

Two labels with the same value:

text
L03c.java:6: error: duplicate case label
            case 1: System.out.println("b"); break;
            ^

A double selector:

text
L03c.java:9: error: selector type double is not allowed
        switch (d) {
               ^

(The messages were produced by JDK 21 and may differ slightly in other versions.)

Mistake 4: Leaving out default

  • Incorrect: a switch over a menu option with no default; an invalid option silently does nothing.
  • Correct: add a default that reports the bad value.

Mistake 5: Wrong letter case with strings

"STOP" does not match case "stop":. Normalize the text first or list every spelling you accept.

Exercises

Level A: Foundation

A1. Predict the output for n = 2:

java
switch (n) {
    case 1: System.out.println("one"); break;
    case 2: System.out.println("two");
    case 3: System.out.println("three"); break;
    default: System.out.println("other");
}

What is printed for n = 1, n = 3, and n = 9?

Show solution A1

A1. For n = 2: two and then three, because there is no break after two. n = 1: one. n = 3: three. n = 9: other.

A2. Which of these selector types are allowed in a classic switch: int, String, double, char, boolean?

Show solution A2

A2. int, String, and char are allowed. double and boolean are not.

A3. In one sentence: what is fall-through?

Show solution A3

A3. Fall-through means that when a case has no break, execution continues into the statements of the next label instead of leaving the switch.

Level B: Application

B1. Write a switch that turns an int day number (1 to 7, Monday is 1) into a name, with Unknown day for anything else. Use break correctly.

Show solution B1

B1.

java
String name;
switch (day) {
    case 1: name = "Monday"; break;
    case 2: name = "Tuesday"; break;
    case 3: name = "Wednesday"; break;
    case 4: name = "Thursday"; break;
    case 5: name = "Friday"; break;
    case 6: name = "Saturday"; break;
    case 7: name = "Sunday"; break;
    default: name = "Unknown day";
}

B2. A parking machine charges by vehicle code: 'C' car costs 5, 'M' motorbike costs 2, 'T' and 'B' (truck and bus) cost 12, anything else prints Unknown vehicle. Write it with a char selector and grouped labels.

Show solution B2

B2.

java
int fee;
switch (code) {
    case 'C':
        fee = 5;
        break;
    case 'M':
        fee = 2;
        break;
    case 'T':
    case 'B':
        fee = 12;
        break;
    default:
        System.out.println("Unknown vehicle");
        fee = 0;
}

B3. The code below should print Closed for Sunday (7) only, but it prints more. Predict the output for day = 7 and fix it.

java
switch (day) {
    case 7:
        System.out.println("Closed");
    default:
        System.out.println("Open");
}
Show solution B3

B3. For day = 7 it prints Closed and then Open, because label 7 falls into default. Fix: add break; after the Closed line.

Level C: Challenge

C1. Rewrite this switch as an if chain, then explain which version you would keep and why.

java
switch (code) {
    case 200: msg = "OK"; break;
    case 404: msg = "Not found"; break;
    case 500: msg = "Server error"; break;
    default:  msg = "Other";
}
Show solution C1

C1.

java
if (code == 200) { msg = "OK"; }
else if (code == 404) { msg = "Not found"; }
else if (code == 500) { msg = "Server error"; }
else { msg = "Other"; }

Either is correct. The switch states "one value against several constants" and avoids repeating code ==. The if chain cannot fall through by accident. Both answers are acceptable if justified; the arrow form in the next lesson combines both benefits.

C2. A shop gives a discount percent by a customer score from 0 to 100: 0 to 49 gives 0, 50 to 79 gives 5, 80 to 100 gives 10. A classmate says "use a switch on score / 10". Explain how that could work, list the labels you would need, and say whether you prefer it to an if chain.

Show solution C2

C2. score / 10 is integer division, so 0 to 49 give 0 to 4, 50 to 79 give 5 to 7, and 80 to 99 give 8 and 9, and 100 gives 10. Labels: case 0: case 1: case 2: case 3: case 4: for 0, case 5: case 6: case 7: for 5, case 8: case 9: case 10: for 10. It works only because the boundaries sit at multiples of 10, it breaks if a boundary moves to 75, and it accepts -5 / 10, which is 0 in integer division, so negative scores need a separate check. An if chain with >= 80 and >= 50 is clearer and safer here.

Mini Challenge

Write a small "traffic light" program with String light set to "red", "yellow", or "green". Use a classic switch to print Stop, Get ready, or Go, and a default that prints Light is broken. Then deliberately remove one break, predict what changes before running, and run it. Finally restore the break.

Check your work: you predicted the extra output correctly, and you can point at the label where execution entered and the label it fell into.

Summary & Next Lesson

Key takeaways

  • switch compares one selector value for equality against constant case labels; it suits fixed choices, not ranges.
  • Execution starts at the matching label and continues until break or the end of the switch. Without break it falls through.
  • Grouped labels (case 6: case 7:) share an action on purpose; any other fall-through is probably a bug.
  • Classic switch allows char, byte, short, int, wrappers, String, and enums, not long, double, or boolean.
  • Include a default for unexpected values.

Next lesson

The classic switch works but is easy to get wrong. The next lesson, "Switch expressions (modern Java)", introduces the arrow form that never falls through and can produce a value directly.

Self-check

  1. What starts running when no label matches and there is a default?
  2. What happens to the code after a matched label if there is no break?
  3. Can a case label contain score >= 80?
  4. Why is double rejected as a selector type?
  5. Name one decision better suited to switch and one better suited to else if.
Show answers
  1. The default block.
  2. It keeps running into the following labels' statements until a break or the end of the switch.
  3. No: a label must be a constant, and ranges need an if chain.
  4. The classic switch is defined only for the listed integer-like types, wrappers, strings, and enums; the specification does not allow double.
  5. Switch: day number to name. Else-if: score to grade (ranges).

References

  • Oracle, The Java Language Specification, Java SE 21, Chapter 14, section on the switch statement. Supports the rules that old-style labels fall through, that arrow rules do not, which selector types are allowed, and that duplicate constants are an error.
  • The outputs and compiler messages were produced with JDK 21; wording may vary in other versions.

Practice

Apply this lesson with the module's lab, exercises and quiz.

Lab and exercises Quiz

Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.

Continue to next lesson

Type to search levels, phases, modules and lessons.