W3docs

Java Switch Expressions

Modern switch expressions in Java with arrow syntax, yield, and exhaustive pattern matching.

Java 14 promoted switch expressions to a standard language feature. They build on the traditional switch statement with three big improvements: they produce a value, they use a cleaner arrow syntax, and they make fall-through impossible. If you're on Java 14 or newer, prefer them.

This chapter covers the arrow syntax, the yield keyword for block bodies, exhaustiveness checking, and the type-based pattern matching that became standard in Java 21. By the end you'll know when to reach for a switch expression instead of an if/else chain.

Statement vs. expression

The traditional switch is a statement: it does something (runs side effects) but produces no value. A switch expression evaluates to a value you can assign, return, or pass to a method. That single difference drives everything else on this page — because the result is used, the compiler can demand that every branch yields a value and that no input slips through unhandled.

Arrow-form syntax

String day = "TUE";

String label = switch (day) {
  case "MON", "TUE", "WED", "THU", "FRI" -> "weekday";
  case "SAT", "SUN" -> "weekend";
  default -> "unknown";
};

Three things to notice:

  1. The whole switch is an expression — it evaluates to a value you can assign (note the trailing ;).
  2. Each case uses -> instead of :. The right-hand side is one statement or expression.
  3. Multiple labels are allowed in one case, comma-separated. No break, no fall-through.

Block bodies with yield

If a case needs multiple statements, use a block — and inside the block, return the value with yield:

int score = 78;

String grade = switch (score / 10) {
  case 10, 9 -> "A";
  case 8 -> "B";
  case 7 -> {
    System.out.println("close to B");
    yield "C";
  }
  case 6 -> "D";
  default -> "F";
};

yield is like return, but for the switch expression — it sets the value of this switch and exits the case. (Don't confuse it with return, which would exit the enclosing method.)

You only need yield inside a block ({ ... }). A single-expression case like case 8 -> "B"; already returns its value directly, so adding yield there would be a compile error.

Info

yield is a contextual keyword: it only acts as a keyword inside a switch block. Code that used yield as a variable or method name before Java 14 still compiles, so adopting switch expressions never breaks existing identifiers.

Statements still work

You can use arrow syntax for side effects too, in which case it's a statement, not an expression:

switch (day) {
  case "MON", "TUE", "WED", "THU", "FRI" -> System.out.println("weekday");
  case "SAT", "SUN" -> System.out.println("weekend");
  default -> System.out.println("unknown");
}

The benefit over the old form: no break, no fall-through bugs, plus the multi-label cases above.

Exhaustiveness

When a switch expression assigns to a variable, the compiler requires that every possible input produces a value. For an enum, that means either covering all constants or providing a default:

enum Status { PENDING, ACTIVE, DONE }

Status s = Status.ACTIVE;

String label = switch (s) {
  case PENDING -> "waiting";
  case ACTIVE  -> "running";
  case DONE    -> "complete";
};   // no default needed — all enum values are covered

If you later add a new constant to the enum and forget to update the switch, the compiler will tell you. That's a strong correctness guarantee you don't get with if/else.

Pattern matching (Java 21+)

Java 21 made pattern matching for switch a standard feature. You can switch on the type of a value, and bind it to a typed variable inside the case:

Object o = 42;

String description = switch (o) {
  case Integer i when i < 0 -> "negative int: " + i;
  case Integer i             -> "non-negative int: " + i;
  case String s              -> "string of length " + s.length();
  case null                  -> "null value";
  default                    -> "something else";
};

The when clause is a guard — it narrows a case further with a boolean condition. This replaces a lot of instanceof chains, and it pairs naturally with the broader pattern matching features.

Two rules to keep in mind:

  • A traditional switch rejects a null selector with a NullPointerException. A pattern switch may include an explicit case null — without it, a null still throws. Letting null reach the switch quietly is no longer possible to miss.
  • Cases are tested top to bottom, so order from most specific to most general. The guarded case Integer i when i < 0 must come before the plain case Integer i, or the unguarded case would swallow every integer first.

A worked example

java— editable, runs on the server

What's next

We've covered conditionals. Next come the loops: the while loop is the simplest of them.

Practice

Practice
Inside an arrow-form switch expression with a block body, which keyword returns the value of that case?
Inside an arrow-form switch expression with a block body, which keyword returns the value of that case?
Was this page helpful?