All topics
library
intermediate

Switch Expressions & Pattern Matching

Use modern switch as an expression with arrow syntax, pattern matching, and guarded patterns.

Modern switch returns a value, does not fall through, and can match types.

Old switch = a vending machine with numbered buttons (limited to specific values). New switch = a smart assistant that can identify what you hand it (pattern matching) and always gives you something back (expression).

Key Concepts

1
    String label = switch (day) {
      case MON, TUE, WED, THU, FRI -> "weekday";
      case SAT, SUN                -> "weekend";
    };
2
The arrow removes break. The old form fell through by default, so a forgotten break ran the next case too — a bug the arrow form cannot express.
break
3
yield returns from a multi-statement case:
    int size = switch (type) {
      case SMALL -> 1;
      case LARGE -> {
        log("large order");
        yield 10;
      }
    };
yield
4
An expression must be exhaustive. Cover every value or add default, or it will not compile — unlike the old statement form, which silently did nothing on an unmatched value.
default
5
Type patterns arrived in Java 21.
    String describe(Object o) {
      return switch (o) {
        case Integer i -> "int: " + i;
        case String s  -> "string of " + s.length();
        case null      -> "null";
        default        -> "something else";
      };
    }
6
case null is new and matters. Before Java 21, switch threw NullPointerException on a null selector, so every switch needed a null check in front of it. Now you handle it as a case — and if you do not, it still throws, so nothing silently changed.
case nullswitchNullPointerException
7
Guarded patterns add a condition with when:
when
8
    case Integer i when i > 100 -> "big";
    case Integer i              -> "small";
9
Order matters: the guarded case must come first, or the unguarded one catches everything.
10
Record patterns destructure:
    case Point(int x, int y) -> x + y;
11
With a sealed type, default becomes unnecessary — and leaving it out is better, because adding a subtype then breaks the build instead of falling into default.
default
12
What the interviewer is probing.1. "What does the arrow form change besides syntax?" Probing: fall-through. Stalls: "It is tidier." Moves up: no fall-through, so a forgotten break cannot run the next case, and as an expression it must be exhaustive.
13
2. "What happens on a null selector?" Probing: the behaviour that changed in 21. Stalls: "It matches default." Moves up: it threw NullPointerException before Java 21; now you can write case null, and without it, it still throws.
14
3. "How do you return a value from a multi-statement case?" Probing: yield. Stalls: "With return." Moves up: yield — return would leave the enclosing method.
15
4. "Why must a guarded pattern come before the unguarded one?" Probing: ordering. Stalls: "Order does not matter." Moves up: cases are tested in order, so an unguarded case Integer i would catch everything before the guarded case Integer i when i > 100 was reached.