Java Switch Expression with Enum Types
java switch expression enum: Learn how to use Java switch expressions with enums, including arrow syntax, yield, exhaustiveness, and practical examples.
java switch expression enum requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
When you combine a Java switch expression with an enum, you get a concise way to map each constant to a value or action. Unlike the classic switch statement, a switch expression can produce a result, and the compiler can verify that every enum constant is covered. This removes a whole class of runtime errors that occur when a new enum value is added but the switch is not updated.
What a Switch Expression Changes for Enum Handling
Before switch expressions, handling an enum with a switch meant writing a statement that assigned a variable inside each branch. The compiler did not enforce that all constants were handled, so a missing case would silently leave the variable null or at its default value. A switch expression changes that contract: if you use it as an expression, the compiler requires that the set of cases is exhaustive for the enum type. This is a compile-time guarantee that every possible input produces a value.
For example, consider an enum representing order statuses:
public enum OrderStatus { NEW, PROCESSING, SHIPPED, DELIVERED, CANCELLED }
With a traditional switch statement, you might write:
String label; switch (status) { case NEW: label = "New"; break; case PROCESSING: label = "Processing"; break; // ... }
If you forget DELIVERED, label stays null. The switch expression approach forces you to handle every constant, and it returns a value directly.
Basic Syntax: Arrow Labels and the Yield Keyword
A switch expression uses arrow labels (->) instead of colons, and each branch can be a single expression, a block, or a throw statement. When a branch needs to produce a value, you use the yield keyword inside a block. Here is the same status mapping as a switch expression:
String label = switch (status) { case NEW -> "New"; case PROCESSING -> "Processing"; case SHIPPED -> "Shipped"; case DELIVERED -> "Delivered"; case CANCELLED -> "Cancelled"; };
The arrow syntax makes the code more readable because each case is a one-liner. If a branch requires multiple statements, wrap it in a block and use yield to return the value:
int priority = switch (status) { case NEW -> { System.out.println("New order"); yield 1; } case PROCESSING -> 2; case SHIPPED -> 3; case DELIVERED -> 4; case CANCELLED -> 0; };
Notice that yield is only needed inside a block. A single expression after the arrow is implicitly the result.
Exhaustiveness and the Compiler's Role
The most valuable property of a switch expression over an enum is exhaustiveness. If you omit one of the enum constants, the code will not compile. For the OrderStatus enum, removing the CANCELLED case produces an error like:
the switch expression does not cover all possible input values
This is a compile-time check, so the failure is caught during development, not in production. When you later add a new constant to the enum, every switch expression that uses it must be updated. This is a deliberate design decision: it forces you to consider the new state everywhere it matters.
There is one exception: if the switch expression has a default branch, it is considered exhaustive even if some enum constants are missing. Using default is a way to opt out of the compiler's exhaustive check, but it also means you lose the safety net. For an enum, you usually want the compiler to verify all constants, so prefer listing them explicitly unless you have a good reason to handle unknown values.
Returning Values from a Switch Expression
A switch expression can be assigned to a variable, passed as an argument, or used in a return statement. This makes it a natural fit for mapping an enum to a related value, such as a display name, a numeric code, or a configuration object.
public static int statusCode(OrderStatus status) { return switch (status) { case NEW -> 100; case PROCESSING -> 200; case SHIPPED -> 300; case DELIVERED -> 400; case CANCELLED -> 500; }; }
Because the switch expression is an expression, it can be used in a lambda or a method reference. For example, you can create a Function<OrderStatus, String> that uses a switch expression internally:
Function<OrderStatus, String> labelProvider = status -> switch (status) { case NEW -> "New"; case PROCESSING -> "Processing"; case SHIPPED -> "Shipped"; case DELIVERED -> "Delivered"; case CANCELLED -> "Cancelled"; };
This is concise and keeps the mapping logic in one place.
Handling Multiple Enum Constants in One Branch
Sometimes several enum constants should map to the same result. You can combine them in a single case using a comma-separated list. This is especially useful when you want to group related states.
boolean isActive = switch (status) { case NEW, PROCESSING, SHIPPED -> true; case DELIVERED, CANCELLED -> false; };
The compiler still enforces exhaustiveness: every constant must appear in at least one case. This grouping reduces duplication and makes the intent clearer than writing separate branches that return the same value.
Switch Expressions with Enum-Specific Methods
Enums in Java can have fields and methods. A switch expression can be used inside an enum method to provide behavior that depends on the constant. This is a common pattern when the logic is too complex to fit into a single method per constant.
public enum Operation { ADD, SUBTRACT, MULTIPLY, DIVIDE; public double apply(double a, double b) { return switch (this) { case ADD -> a + b; case SUBTRACT -> a - b; case MULTIPLY -> a * b; case DIVIDE -> { if (b == 0) { throw new ArithmeticException("Division by zero"); } yield a / b; } }; } }
Here the switch expression is exhaustive because this is an Operation, and all four constants are covered. The DIVIDE branch uses a block to include a validation check before yielding the result. This pattern keeps the operation logic attached to the enum, which is more maintainable than a separate utility method with a switch.
Performance and Bytecode Considerations
Switch expressions on enums compile to the same bytecode as switch statements on enums. The JVM uses a lookup table or a jump table depending on the number of constants and their ordinal values. The compiler may also generate a synthetic $SwitchMap$ array that maps enum ordinals to switch case indices. This is an implementation detail, but it means there is no meaningful performance penalty for using a switch expression instead of a traditional switch statement.
The main performance consideration is not the switch itself but what you do inside each branch. If a branch performs expensive work, that work happens regardless of the syntax. The exhaustiveness check happens at compile time, so there is no runtime overhead from validation. In practice, you can use switch expressions freely without worrying about a performance regression.
Common Mistakes and Compatibility Notes
One common mistake is using return inside a block instead of yield. In a switch expression, a block that is supposed to produce a value must end with a yield statement. Using return will cause a compile error because the block is not a method body. Another mistake is forgetting the semicolon after the closing brace of the switch expression when it is assigned to a variable. The semicolon is required because the switch expression is a statement in that context.
Compatibility is also worth checking. Switch expressions were introduced as a final feature in Java 14, after being previewed in Java 12 and 13. If your project uses an older Java version, you cannot use this syntax. The arrow labels and yield keyword are not available in Java 11 or earlier. For a project that must target Java 8 or 11, you will need to stick with the traditional switch statement or use a different pattern like a Map<Enum, Function>.
When you do upgrade, be aware that the exhaustiveness check can surface missing cases that were previously hidden. This is a feature, but it may require updating existing switch statements that were not exhaustive. The compiler will guide you through the changes, and the result is more robust code.