switch Statement in Java – From Classic switch to Pattern Matching
The switch statement chooses one of many code paths based on a single value. Instead of a long if-else-if chain comparing the same variable again and again, you list the possible values as case labels and Java jumps straight to the matching one.
Switch has changed a lot in recent Java versions. This tutorial starts with the classic form and break, then covers switch expressions with arrows and yield (Java 14), and finally pattern matching for switch (Java 21).
1. The Classic switch Statement
switch (expression) {
case value1:
// statements
break;
case value2:
// statements
break;
default:
// runs when no case matches
}
public class ClassicSwitch {
public static void main(String[] args) {
int day = 3;
String name;
switch (day) {
case 1:
name = "Monday";
break;
case 2:
name = "Tuesday";
break;
case 3:
name = "Wednesday";
break;
default:
name = "Another day";
}
System.out.println("Day " + day + " is " + name);
}
}
Day 3 is Wednesday
- The expression can be
byte,short,char,int, their wrapper classes, aString(Java 7+) or anenum. Since Java 21, any reference type can be used with patterns. - Case labels must be constants of a compatible type, and no two labels may be equal.
defaultis optional and can appear anywhere, though it is usually placed last.breakends the switch.
2. Fall-Through and Grouped Cases
In the classic form, when a case matches, Java runs its statements and then keeps going into the following cases until it reaches a break or the end. This is called fall-through. It is occasionally useful, but forgetting a break is a common bug.
public class FallThrough {
public static void main(String[] args) {
// Without break, execution "falls through" to the next case
int level = 2;
System.out.println("Unlocked features for level " + level + ":");
switch (level) {
case 3:
System.out.println(" - analytics");
case 2:
System.out.println(" - export");
case 1:
System.out.println(" - basic editing");
}
// Grouping several labels on one case
char grade = 'B';
switch (grade) {
case 'A': case 'B':
System.out.println("Grade " + grade + ": excellent");
break;
case 'C':
System.out.println("Grade " + grade + ": good");
break;
default:
System.out.println("Grade " + grade + ": needs improvement");
}
}
}
Unlocked features for level 2: - export - basic editing Grade B: excellent
Level 2 printed its own feature and then fell through to level 1's feature, which is intended here. The grade example shows how to give several labels the same code.
3. Switch Expressions (Java 14+)
Modern Java offers arrow labels (case X ->) and lets a switch produce a value. Arrow cases never fall through, so no break is needed, and several constants can share one case with commas.
public class SwitchExpression {
enum Size { SMALL, MEDIUM, LARGE, XL }
public static void main(String[] args) {
// Arrow labels: no fall-through, no break needed (Java 14+)
String month = "FEB";
int days = switch (month) {
case "APR", "JUN", "SEP", "NOV" -> 30;
case "FEB" -> 28;
default -> 31;
};
System.out.println(month + " has " + days + " days");
// With enums, the compiler checks that every constant is handled
Size size = Size.LARGE;
double price = switch (size) {
case SMALL -> 199;
case MEDIUM -> 249;
case LARGE, XL -> {
double base = 299;
yield size == Size.XL ? base + 50 : base; // yield returns a value from a block
}
};
System.out.println(size + " costs " + price);
}
}
FEB has 28 days LARGE costs 299.0
- A switch expression must be exhaustive: every possible value must be handled, usually with
default. For enums, listing every constant is enough, and the compiler will tell you if you miss one. - When a case needs several statements, use a block
{ }and return its value withyield. - Arrow labels can also be used in switch statements that produce no value.
4. Pattern Matching for switch (Java 21)
Since Java 21, a switch can match on types and record patterns, add when guards, and even handle null explicitly:
public class PatternSwitch {
sealed interface Shape permits Circle, Rectangle, Triangle { }
record Circle(double radius) implements Shape { }
record Rectangle(double width, double height) implements Shape { }
record Triangle(double base, double height) implements Shape { }
// Java 21: switch on types, with record patterns and guards
static String describe(Object obj) {
return switch (obj) {
case null -> "nothing";
case Integer i when i > 100 -> "a big number " + i;
case Integer i -> "a number " + i;
case String s -> "text of length " + s.length();
case Circle(double r) -> String.format("a circle with area %.2f", Math.PI * r * r);
case Rectangle(double w, double h) -> "a rectangle with area " + (w * h);
default -> "something else: " + obj.getClass().getSimpleName();
};
}
public static void main(String[] args) {
Object[] things = {7, 250, "hello", new Circle(1), new Rectangle(2, 3), new Triangle(3, 4), null};
for (Object t : things) {
System.out.println(describe(t));
}
}
}
a number 7 a big number 250 text of length 5 a circle with area 3.14 a rectangle with area 6.0 something else: Triangle nothing
case Integer imatches anyIntegerand binds it toi.case Integer i when i > 100adds a guard condition. More specific cases must come before more general ones.case Circle(double r)deconstructs a record into its components.case nullhandles anullvalue; without it, switching onnullthrowsNullPointerException.- With a
sealedinterface, a switch that covers every permitted subtype needs nodefault.
5. Classic vs Arrow vs Pattern Switch
| Feature | Classic (case X:) | Arrow (case X ->) | Pattern (Java 21) |
|---|---|---|---|
| Fall-through | Yes, unless break | No | No |
| Can return a value | Only as an expression with yield | Yes | Yes |
| Multiple labels | case 1: case 2: | case 1, 2 -> | Type patterns |
| Matches on | Constants | Constants | Types, records, guards, null |
| Exhaustiveness checked | No (statements) | Yes (expressions) | Yes |
6. switch vs if-else
- Use switch when one value is compared against many constants, enum values or types.
- Use if-else for ranges (
marks >= 85), unrelated conditions or combinations with&&/||(although guards make switch more flexible too). - For large constant mappings, a
Maplookup may be simplest of all.
7. Common Mistakes
- Forgetting
breakin a classic switch and falling through by accident. - Switching on a
nullStringor wrapper withoutcase null:NullPointerException. - Using variables or ranges as case labels; labels must be constants (use guards or if-else for ranges).
- Putting a general pattern before a specific one: the compiler reports the later case as dominated.
- Switching on
long,float,doubleorbooleanvalues with constant labels, which is not allowed.
8. Summary
- The classic switch jumps to a matching
caseand needsbreakto avoid fall-through. - Switch works with integers,
char, strings, enums and wrappers, and with any type when using patterns. - Arrow labels and switch expressions (Java 14) remove fall-through and return values with
yield. - Pattern matching for switch (Java 21) matches types and records, supports guards and
case null. - Prefer modern arrow switches in new code.
Related Tutorials
Reference: dev.java: Branching with Switch Expressions
Frequently Asked Questions (FAQ)
Q1. What is a switch statement in Java?
A control statement that compares one value against a list of case labels and runs the code of the matching case, or the default case if none match.
Q2. Which data types can be used in a switch?
byte, short, char, int, their wrappers, String and enums with constant labels. Since Java 21, any reference type can be used with type patterns. long, float, double and boolean cannot be used with constant labels.
Q3. What happens if I forget break in a switch?
In a classic switch, execution falls through into the next case and keeps running statements until a break or the end of the switch. Arrow cases (->) never fall through.
Q4. Is default mandatory in a switch?
Not in a classic switch statement. A switch expression must be exhaustive, so it needs default unless all values are covered, for example all constants of an enum or all subtypes of a sealed interface.
Q5. Can I use strings in a switch?
Yes, since Java 7. Matching uses equals(), so it is case-sensitive. Switching on a null string throws NullPointerException unless you add case null (Java 21).
Q6. What is a switch expression?
A switch that produces a value (Java 14+), for example int days = switch (month) { case "FEB" -> 28; default -> 31; };. It must cover all possible values.
Q7. What does yield do in a switch?
It returns a value from a case block in a switch expression: case X -> { ...; yield result; }. It is like return, but for the switch rather than the method.
Q8. What is the difference between case X: and case X ->?
The colon form allows fall-through and needs break. The arrow form runs only the code for that case, can list several constants with commas, and works naturally in switch expressions.
Q9. Can a case label be a variable?
No. Constant case labels must be compile-time constants (literals, final constants or enum names). Use when guards or if-else for values only known at runtime.
Q10. Can I switch on a range of values?
Not directly. Use if-else for ranges, or a pattern case with a guard: case Integer i when i >= 90 -> "A";.
Q11. What is pattern matching for switch?
A Java 21 feature that lets case labels test an object's type and bind it to a variable (case String s), deconstruct records, use when guards and handle null.
Q12. Can switch handle null?
Before Java 21, switching on null always threw NullPointerException. Since Java 21 you can add case null to handle it explicitly.
Q13. Is switch faster than if-else?
For many integer constants, the compiler can generate a jump table, which can be faster than a long chain of comparisons. For a few cases the difference is negligible; choose the clearer form.
Q14. Can I use switch with enums?
Yes. Write the constant names without the enum type: case RED -> .... A switch expression over an enum is exhaustive when every constant is listed.
Q15. Can a switch be nested?
Yes, a switch can appear inside a case of another switch, but this quickly hurts readability. Extract the inner switch into a method.
Q16. Where can default appear in a switch?
Anywhere among the cases in a classic switch, but by convention it comes last. With patterns, it must not dominate later cases.
Q17. Can I return from a method inside a switch case?
Yes, in a switch statement a return exits the whole method. In a switch expression, use yield to give the expression its value instead.
Q18. What does "dominated" mean in a pattern switch?
A case is dominated when an earlier case already matches everything it could match, for example case Integer i before case Integer i when i > 100. The compiler rejects it because it can never be reached.
Q19. Do I need break after the last case?
Not technically, because there is nothing left to fall into, but many developers add it so that adding a new case later does not create a fall-through bug.
Q20. Which Java versions added the switch improvements?
Strings in switch arrived in Java 7, switch expressions with arrows and yield became standard in Java 14, and pattern matching for switch with record patterns became standard in Java 21.