Switch expressions in Java
Arrow labels, no fall-through, yield, exhaustiveness.
A switch that returns
Since Java 14, switch can be an expression: it produces a value you can assign or return. Note the semicolon after the closing brace, because the whole thing is part of an assignment statement.
String size = switch (n) {
case 1, 2 -> "small";
case 3 -> "medium";
default -> "large";
};Arrows never fall
An arrow label case X -> runs only its own arm. There is no fall-through, so no break is needed. Several values share an arm with commas: case 1, 2 ->.
int code = 2;
switch (code) {
case 1 -> System.out.println("one");
case 2 -> System.out.println("two");
case 3 -> System.out.println("three");
} // prints only: twoYour turn
n is 3. What prints?
int n = 3;
String r = switch (n) {
case 1 -> "one";
case 2, 3 -> "few";
default -> "many";
};
System.out.println(r);fewfew manymanyCompile error
Show the answer
few. 3 matches case 2, 3, that single arm produces the value, and the switch is done. Arrow arms never fall through.
yield: the value of a block arm
When an arm needs several statements, give it a { } block and finish with **yield value;** to hand back the result. You can't use return there: it would try to leave the whole method, which isn't allowed from inside a switch expression.
int pts = switch (grade) {
case 'A' -> 4;
case 'B' -> {
System.out.println("ok");
yield 3;
}
default -> 0;
};It must cover everything
A switch expression must be exhaustive: every possible input needs a result. For an int or char that means a default. For an enum, listing all its constants is enough. Miss a case and it's a compile error, not a runtime surprise.
int n = 5;
String r = switch (n) {
case 1 -> "one";
case 2 -> "two";
}; // compile error: no defaultYour turn
What happens here?
char g = 'B';
int pts = switch (g) {
case 'A' -> 4;
case 'B' -> 3;
};
System.out.println(pts);Prints 3Prints 0Compile error
Show the answer
Compile error. A char has 65,536 possible values and only two are covered. A switch expression with no default here isn't exhaustive, so it never even runs.
Old labels, new switch?
Can classic colon labels (case 6:) appear inside a switch *expression*?
Think about it, then reveal the answer
Yes. Colon labels still fall through, so case 6: case 7: yield "weekend"; works: execution falls from 6 into 7, and **yield both produces the value and leaves the switch**. Arrows are usually cleaner, though.
In real projects
Exhaustiveness is a safety net. Add a new constant to an enum (say a new payment type) and every switch expression that forgot it stops compiling, instead of silently doing nothing in production. That's a big reason modern Java code prefers switch expressions.
Key takeaways
- case 1, 2 -> "small"; runs only that arm, no break needed
- In a { } block arm, yield value; produces the result
- Must cover every value: usually with default (or all enum constants)
- The whole switch expression ends with a semicolon when assigned
💡 A switch expression is a vending machine: press a button (the value) and exactly one item comes out, and every button must give something.
In Java 12's preview, switch expressions returned values with break "value";. Java 13 replaced that with the brand-new word yield, and the feature became final in Java 14.
Practice questions
What does this print?
int n = 2;
String r = switch (n) {
case 1 -> "one";
case 2 -> "two";
case 3 -> "three";
default -> "many";
};
System.out.println(r);- two three many
- two
- many
- Compile error
Check your answer
two. n is 2, so the expression evaluates to "two". Arrow arms never fall through.
What does this print?
int n = 5;
String r = switch (n) {
case 1 -> "one";
case 2 -> "two";
};
System.out.println(r);- null
- Compile error
- An empty line
- Throws MatchException
Check your answer
Compile error. A switch expression must produce a value for every possible int. With no default it isn't exhaustive, so the compiler rejects it.