Java Switch Expressions (Java 14+)
Switch expressions, standardized in Java 14 (JEP 361), let switch produce a value directly. Combined with arrow-case syntax, they eliminate fall-through bugs, reduce boilerplate, and integrate naturally with pattern matching introduced in later Java versions.
Contents
Arrow-case Syntax
The arrow ->:breakthrow
// Old style — fall-through prone, verbose
int numLetters;
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
case THURSDAY:
case SATURDAY:
numLetters = 8;
break;
case WEDNESDAY:
numLetters = 9;
break;
default:
throw new IllegalArgumentException("Unknown day: " + day);
}
// New style — switch expression with arrow syntax
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
// No default needed: Day is an enum — compiler checks exhaustiveness
Returning Values with yield
When a case body is a block (not a single expression), use yieldyield
int result = switch (input) {
case "one" -> 1;
case "two" -> 2;
case "three" -> 3;
default -> {
// block body — must use yield to produce the value
System.out.println("Unknown input: " + input);
yield -1;
}
};
// yield also works with colon-style cases (traditional syntax)
int score = switch (grade) {
case 'A':
System.out.println("Excellent!");
yield 100;
case 'B':
yield 85;
case 'C':
yield 70;
default:
yield 0;
};
yieldExhaustiveness
A switch expression (one that produces a value) must cover all possible values. For enums, the compiler checks that every constant is handled. For other types, a defaultcase null, default
enum Season { SPRING, SUMMER, AUTUMN, WINTER }
// Exhaustive — all 4 enum constants are covered, no default needed
String activity = switch (season) {
case SPRING -> "Gardening";
case SUMMER -> "Swimming";
case AUTUMN -> "Hiking";
case WINTER -> "Skiing";
};
// If you add a new enum constant (e.g., MONSOON) without updating
// the switch, it becomes a compile-time error — not a silent runtime bug.
// For String/int selectors — default is required
String category = switch (statusCode) {
case 200, 201 -> "Success";
case 400 -> "Bad Request";
case 401, 403 -> "Auth Error";
case 404 -> "Not Found";
case 500 -> "Server Error";
default -> "Unknown (" + statusCode + ")";
};
Multiple Labels per Case
Multiple case labels can be combined on a single case using commas, both in arrow and traditional syntax:
// Multiple constants → same result
String type = switch (ch) {
case 'a', 'e', 'i', 'o', 'u',
'A', 'E', 'I', 'O', 'U' -> "vowel";
default -> "consonant";
};
// Switch expression used directly as a method argument
System.out.println(switch (month) {
case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER, DECEMBER -> 31;
case APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30;
case FEBRUARY -> year % 4 == 0 ? 29 : 28;
});
Practical Examples
Switch expressions are most valuable for mapping a finite set of inputs to output values: enum constants to labels, status codes to categories, type tokens to behavior. The arrow form (case X -> resultyield
// HTTP status classifier
record HttpStatus(int code, String phrase) {}
String classify(int code) {
return switch (code / 100) {
case 1 -> "Informational";
case 2 -> "Success";
case 3 -> "Redirection";
case 4 -> "Client Error";
case 5 -> "Server Error";
default -> "Unknown";
};
}
// Switch expression assigning to a var
var description = switch (shape) {
case Circle c -> "Circle with radius " + c.radius();
case Rectangle r -> "Rectangle " + r.width() + "x" + r.height();
default -> "Unknown shape";
};
// Nested switch expressions
String priority = switch (severity) {
case CRITICAL -> switch (environment) {
case PRODUCTION -> "P0 - Page immediately";
case STAGING -> "P1 - Fix before release";
default -> "P2 - Fix soon";
};
case HIGH -> "P2 - Fix soon";
case MEDIUM -> "P3 - Schedule";
case LOW -> "P4 - Backlog";
};