Skip to content

VOL 01 / CH 04 / LESSON 02

4.2 switch Statements and Expressions ​

Prerequisites: Conditional branches and Java 17 basic syntax Estimated time: 30 minutes You are ready to continue when: You can distinguish traditional colon branches, arrow branches, and switch expressions

Traditional switch Statements ​

java
String item = "book";

switch (item) {
    case "book":
        System.out.println("50 credits");
        break;
    case "magazine":
        System.out.println("40 credits");
        break;
    case "notebook":
        System.out.println("35 credits");
        break;
    default:
        System.out.println("unknown item");
}

This page uses final Java 17 syntax without preview features. A switch selector supports byte, short, char, and int, as well as their corresponding wrapper types, enums, and String. It does not support long, float, double, or boolean. A null wrapper, enum, or String selector throws NullPointerException; arrow labels and default do not catch it. Handle null before entering the switch.

Colon Branches Can Fall Through ​

Execution starts at the matching case: label. If it does not encounter break, return, throw, or the end of switch, it continues executing the following statements:

java
int day = 6;

switch (day) {
    case 6:
        System.out.println("Saturday");
    case 7:
        System.out.println("weekend");
        break;
    default:
        System.out.println("weekday");
}

When day is 6, it prints two lines. This could be intentionally shared logic, or it could be a missed break. Comment intentional fall-through and test the resulting behavior.

Sharing multiple labels does not require copying empty branches:

java
switch (day) {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        System.out.println("weekday");
        break;
    case 6:
    case 7:
        System.out.println("weekend");
        break;
    default:
        throw new IllegalArgumentException("day: " + day);
}

Arrow Branches Do Not Fall Through ​

Java 14 onwards officially provides arrow syntax, and Java 17 allows direct use:

java
switch (item) {
    case "book" -> System.out.println("50 credits");
    case "magazine" -> System.out.println("40 credits");
    case "notebook" -> System.out.println("35 credits");
    default -> System.out.println("unknown item");
}

When a branch requires multiple statements, use a block:

java
case "book" -> {
    recordSale(item);
    System.out.println("50 credits");
}

Multiple constants can be written under the same label:

java
case "book", "magazine" -> System.out.println("physical item");

switch Expression Return Value ​

java
int price = switch (item) {
    case "book" -> 50;
    case "magazine" -> 40;
    case "notebook" -> 35;
    default -> throw new IllegalArgumentException("item: " + item);
};

This is an expression, and the final declaration statement requires a semicolon. Each normal path must produce a compatible result; a path that abruptly ends with throw does not require a result value.

Block branches provide values through yield:

java
int price = switch (item) {
    case "book" -> {
        int base = 50;
        System.out.println("featured item");
        yield base;
    }
    case "magazine" -> 40;
    default -> 0;
};

yield terminates the current switch expression and provides a result, which is not equivalent to returning from the entire method via return.

Exhaustiveness and default ​

Switch expressions must satisfy the compiler’s exhaustiveness check; that does not make null a fallback case. For open sets of integers or strings, default is typically required. When enumerating all constants of an enum, the compiler can determine completeness. Whether to still include default depends on whether you want new enum constants to trigger a compilation failure when recompiled, or to explicitly handle them with a fallback.

Do not use default -> 0 to hide inputs that should be rejected. Scenarios like price, permissions, protocol states are usually better suited for throwing explicit exceptions or returning a type that can express the absence of a value.

When to Choose switch ​

  • A discrete value mapped to a fixed branch: suitable for switch;
  • Ranges, multiple independent conditions, or complex predicates: if / else if is more natural;
  • Branches that keep growing with each branch containing a lot of behavior: consider enum polymorphism, a mapping table, or a strategy object, rather than infinitely expanding switch.

Python and C++ Boundaries ​

Python 3.10+ has match as structured pattern matching, and its capabilities and semantics go beyond simply renaming Java switch. It does not have the traditional fall-through behavior found in C++ switch.

C++ switch typically uses integer or enumeration selectors, and colon branches can also fall through; it does not have Java's String switch, nor does it have the arrow syntax and yield semantics of Java 17's switch expression.

Professional Reference ​

RequirementJava 17 Choice
Execute only branch actionsswitch statement
Compute a valueswitch expression
Avoid fall-througharrow labels
Multiple statements and return a valuearrow block + yield
Unknown value should faildefault -> throw ...
selector may be nullexplicitly handle before switch

Before Moving On ​

Assign a path to each of "book", the unknown item, and null. Then explain when a colon branch falls through, why an arrow branch doesn't need break, and why yield only passes the value to the switch expression rather than exiting the entire method. Finally, confirm that the selector is not long or boolean.

The next lesson extends one branch decision into repeated processing of ten delivery records.

→ Next: while, for, and traversal

Specification: JLS §14.11: switch Statements, §15.28: switch Expressions.

Built with VitePress | Software Systems Atlas