Switch Expressions
A switch expression is a modern form of switch that produces a value you can assign or return, uses arrow labels with no fall-through, and is checked by the compiler for exhaustiveness.
Learn Switch Expressions in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Before You Start
You should know the classic switch statement and enums . Switch expressions are standard from Java 14 onward.
What You'll Learn
The Big Idea — A Vending Machine, Not a To-Do List
💡 Analogy: The old switch statement is a to-do list: "if it's Monday, do these chores; remember to stop ( break ) or you'll keep doing the next day's chores too." The new switch expression is a vending machine : you put in a value, press the matching button (an arrow arm), and it hands you back exactly one product. No risk of accidentally dispensing every snack below the one you wanted.
That single returned value is the whole point: String role = switch (rank) { ... } ; reads as one clear assignment instead of a mutable variable poked at by many case branches.
1️⃣ A switch That Returns a Value
Put the whole switch on the right of an assignment. Each arm uses case LABEL -> value; . The arrow makes each arm self-contained — there is no break , and no fall-through. Note the whole expression ends with a semicolon, just like any other assignment.
2️⃣ Block Arms, yield, and Exhaustive Enums
When an arm needs more than one statement, wrap it in braces and end with yield to supply the value — yield is the switch-expression equivalent of return . And when you switch over an enum and cover every constant, the switch is exhaustive , so you can drop default entirely.
3️⃣ Old Statement vs New Expression
Side by side, the difference is stark. The statement form needs a mutable label variable and a break after each case (forget one and you get a fall-through bug). The expression form assigns a value directly and can never fall through.
4️⃣ Multiple Labels & default
Group values that behave the same with a comma-separated label: case "GET", "HEAD" -> 200; . For open-ended types like String or int you still need a default arm so the switch stays exhaustive.
🧠 Quick Recall
Predict the result before opening each answer.
Answer: No — for an int input it is not exhaustive (what about 3, 4, ...?). error: the switch expression does not cover all possible input values . Add a default .
Answer: A block arm must return its value with yield v; , not break v; . break doesn't produce a value in a switch expression.
Answer: No. Arrow arms never fall through — TUE yields "two" and stops. Only the classic colon form (without break ) falls through.
🎯 Your Turn — Days in a month
Use a switch expression with a multi-label case to map a month number to its day count.
🧩 Mini-Challenge — Tag log levels
Cover every enum constant (so no default ) and use a block arm with yield for one of them.
Common Errors
- ❌ Forgetting the trailing semicolon. A switch expression assignment ends with ; . Fix: var x = switch(...) {...} ; .
- ❌ Using break value; in a block arm. Fix: use yield value; — only yield produces a value.
- ❌ Non-exhaustive switch over int/String. error: does not cover all possible input values . Fix: add a default arm.
- ❌ Mixing arrow and colon styles in one switch. Not allowed. Fix: pick one form for the whole switch.
- ❌ Expecting fall-through with arrows. There is none. Fix: list shared values in one label, e.g. case A, B -> ... .
- ❌ Adding default to an exhaustive enum switch unnecessarily. It silences the helpful error when a new constant is added. Fix: omit it so the compiler reminds you later.
Pro Tips
- 💡 Reach for switch expressions to replace if-else chains that compute one value — they're shorter and exhaustiveness-checked.
- 💡 Prefer enums as the switch subject. You get compile-time exhaustiveness for free and a warning when someone adds a constant.
- 💡 Keep arms tiny. If an arm grows large, extract a method and call it from the arm to keep the switch readable.
- 💡 Pair with assignment to final / var . The value is computed once and never reassigned — cleaner than a mutable accumulator.
📋 Quick Reference
Concept
Syntax
Note
Expression form
var x = switch (k) {...} ;
Produces a value
Arrow arm
case 1 -> "one";
No break, no fall-through
Multiple labels
case 1, 2, 3 -> ...
Share one arm
Block arm
case X -> { ... yield v; }
yield gives the value
Default
default -> ...;
Catches everything else
Enum exhaustive
all constants covered
default optional
Colon form value
case 1: yield x;
yield, not break
Switch on String
switch (s) {...}
Needs default
As a return
return switch (k) {...} ;
Common pattern
Statement form
switch (k) { case 1 -> act(); }
Arrows, no value
Since
Java 14
JEP 361
📚 Resources / Keep Learning
- 📘 Oracle: Switch Expressions and Statements — the official language guide.
- 📗 dev.java: Branching with switch — a guided tutorial.
- 📙 JEP 361: Switch Expressions — the finalizing proposal.
❓ Frequently Asked Questions
🎉 Lesson Complete!
You can now write a switch that returns a value, use arrow arms that never fall through, supply values from block arms with yield , group cases with multiple labels, and rely on exhaustiveness so an enum switch needs no default .
Next up: Pattern Matching — let instanceof and switch bind a typed variable for you.
Practice quiz
What is the key difference between a switch expression and a switch statement?
- Expressions can only use int
- Statements are faster
- A switch expression produces a value you can assign
- Expressions require break
Answer: A switch expression produces a value you can assign. A switch expression evaluates to a value, so you can write var x = switch(...) {...};.
What separator do arrow-style switch labels use?
- -> (arrow)
- : (colon)
- => (fat arrow)
- | (pipe)
Answer: -> (arrow). Arrow labels use ->; the older statement form uses a colon with break.
Do arrow-style switch arms fall through to the next case?
- Yes, like the old switch
- Only without break
- Only for default
- No — each arrow arm runs exactly its own code
Answer: No — each arrow arm runs exactly its own code. Arrow arms never fall through, eliminating the classic missing-break bug.
How do you return a value from a multi-statement { } arm?
- return
- yield value
- break value
- = value
Answer: yield value. Inside a block arm you use yield to supply the arm's value.
How do you match several values in one arm?
- Comma-separate the labels: case 1, 2, 3 ->
- Repeat the case keyword
- Use ||
- Use a range a..b
Answer: Comma-separate the labels: case 1, 2, 3 ->. List the constants separated by commas in a single label: case 1, 2, 3 -> ...
When is a default branch NOT required in a switch expression?
- Never required
- Only for int
- When switching over an enum and all constants are covered
- Only for String
Answer: When switching over an enum and all constants are covered. If every enum constant has an arm, the switch is exhaustive and default is optional.
In which Java version did switch expressions become standard?
- Java 8
- Java 14
- Java 12
- Java 17
Answer: Java 14. Switch expressions previewed in 12/13 and were finalized in Java 14 (JEP 361).
What happens if a switch expression is not exhaustive?
- It returns null
- It throws at runtime
- It returns 0
- It is a compile error
Answer: It is a compile error. A switch expression must cover every possible value; otherwise the compiler rejects it.
Can you still use colon-and-yield together in a switch expression?
- No
- Yes — case 1: yield x; is valid, just without arrows
- Only in Java 21
- Only with enums
Answer: Yes — case 1: yield x; is valid, just without arrows. The colon form of a switch expression uses yield instead of break to produce a value.
Why is the arrow switch considered safer than the classic one?
- It is faster
- It allows null keys
- No fall-through and the compiler enforces exhaustiveness
- It supports more types
Answer: No fall-through and the compiler enforces exhaustiveness. No accidental fall-through plus required exhaustiveness catches whole classes of bugs at compile time.
Continue this course
- Previous: Text Blocks
- Next: Pattern Matching