The switch statement in Java picks one branch out of several based on the value of a single expression, and the arrow form plus switch expressions turn that statement into a compact way to turn a value into a result rather than a stack of if/else assignments. Here is how each form behaves and where each one fits.
How does the classic switch statement work?
In its original form, switch takes one expression and compares it against a list of labels. Each case label holds a constant value, and the body under a label runs when that value matches. The default label catches everything that did not match, and it is optional, though omitting it means unmatched input is silently ignored.
public class GradeSwitch {
public static void main(String[] args) {
String grade = "B";
switch (grade) {
case "A":
System.out.println("Outstanding");
break;
case "B":
System.out.println("Good");
break;
default:
System.out.println("Unknown grade");
}
}
}The output is a single line:
GoodTwo rules govern the original form. The value of the switch expression must be a type that can be compared for equality, which rules out the floating point types, and a break at the end of a case body stops the switch from carrying on into the next case. Neither label needs to be a literal, so you can switch on an enum constant or a final variable as easily as on a string.
What is the arrow form of switch?
The arrow form replaces the colon and the break with an arrow between the label and the body. Each case then stands alone: it runs its body and leaves. There is no implicit fall-through to reason about and no break to forget, which removes the most common switch bug outright.
public class ArrowSwitch {
public static void main(String[] args) {
int day = 3;
switch (day) {
case 1 -> System.out.println("Monday");
case 2 -> System.out.println("Tuesday");
case 3 -> {
System.out.println("Wednesday");
System.out.println("Midweek");
}
default -> System.out.println("Unknown day");
}
}
}A block after the arrow is how you run more than one statement in a case, and because it is a real block you can declare variables inside it without worrying about clashing with another case:
Wednesday
MidweekWhy do cases fall through, and how do I stop it?
In the original form, a case body that does not end with break simply continues into the next case. This is called fall-through, and it is occasionally deliberate: when you want to group several values that share one handler, you stack the labels and put a single body underneath.
public class FallThroughDemo {
public static void main(String[] args) {
int level = 2;
switch (level) {
case 1:
System.out.println("notify the support inbox");
case 2:
System.out.println("write an audit entry");
case 3:
System.out.println("page the on-call engineer");
}
}
}With a level of 2 the output is:
write an audit entry
page the on-call engineerThe first case was skipped because the value was 2, and the third case ran anyway because the second case had no break. That is fall-through working exactly as designed, and also exactly as it bites people who forget the break. In the arrow form the problem cannot occur, which is why it is the better default for new code.
What is a switch expression?
A switch expression is a switch used as a value rather than as a statement. It computes a result, and every path through it has to produce one. The arrow form makes this short, because a single-expression case is its own result.
public class ShippingCost {
public static void main(String[] args) {
int weightKg = 12;
int cost = switch (weightKg) {
case 0, 1 -> 500;
case 2, 3, 4 -> 700;
default -> 700 + (weightKg - 4) * 50;
};
System.out.println("Weight " + weightKg + " kg costs " + cost + " cents");
}
}The output is:
Weight 12 kg costs 1100 centsNote the comma in case 0, 1, which lets one body cover several values without the stacking and fall-through the original form needed. When a case needs more than one statement, use a block and the yield keyword to name the value the block produces.
public class YieldSwitch {
public static void main(String[] args) {
int tier = 3;
int price = switch (tier) {
case 1 -> 1000;
case 2 -> 2000;
default -> {
int base = 3000;
int loyalty = 250;
yield base + loyalty;
}
};
System.out.println("Price: " + price);
}
}That prints Price: 3250. The block assigns two locals and yields the total, and because the whole thing is an expression you can assign it to a variable, pass it as an argument or return it from a method.
Can switch match on types as well as values?
Switch can also branch on the type of the value rather than its contents. The labels become type patterns, and each one binds the matched value to a variable you can use inside the case body.
public class TypeSwitch {
public static void main(String[] args) {
Object payment = 125.50;
String description = switch (payment) {
case Integer i -> "whole-number payment of " + i;
case Double d -> "decimal payment of " + d;
case String s -> "voucher code " + s;
default -> "unrecognised payment";
};
System.out.println(description);
}
}The output is decimal payment of 125.5, because the value is a Double and the Double label comes before the default. Patterns are tested in order, so the most specific label has to be written first.
Quick reference
| Form | Best for | Watch out for |
|---|---|---|
| Classic statement with colon | Codebases that already use it | Fall-through without a break |
| Arrow statement | Dispatching one value to one handler | No fall-through, so grouping needs commas |
| Arrow expression | Turning a value into a result | Every path must produce a value |
| Expression with a block | Multi-step calculations per case | Needs yield inside the block |
| Type patterns | Handling several types in one place | Order matters, most specific first |
Try it yourself: build a small order-status dispatcher. Give it statuses NEW, PAID, SHIPPED and CANCELLED, and use the arrow form to print a different message for each one plus a default for anything unknown. Then convert it into a switch expression that returns the number of days a refund takes for each status, using a block and yield for the CANCELLED case. Finally, write the same logic as an if/else chain and count the lines: switch is usually the shorter and clearer of the two once you have more than three branches.