从 switch 语句到 switch 表达式
在 Java 12 之前,我们使用的是 switch 语句,它有几个明显的限制:

- 只能执行操作,不能返回值:
switch语句块内部不能直接返回一个值,通常我们用它来执行一系列操作,然后通过一个break跳出。 break容易出错:忘记写break会导致“贯穿”(fall-through)现象,这是一个常见的 Bug 来源。- 语法冗长:对于简单的条件判断,
if-else if链可能更简洁。
从 Java 12 开始,引入了 switch 表达式,它解决了上述所有问题:
- 可以返回值:
switch表达式本身可以计算出一个值并返回。 - 消除了“贯穿”:
switch表达式要求每个case必须明确结束,要么使用yield返回一个值,要么使用throw抛出异常,这从根本上杜绝了“贯穿” Bug。 - 语法更现代:支持更简洁的箭头
->语法,以及多常量标签。
switch 表达式的核心特性
返回值
switch 表达式可以像三元运算符或方法调用一样,将结果赋值给一个变量。
示例:
// JDK 12+
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public class SwitchExpressionExample {
public static void main(String[] args) {
Day day = Day.WEDNESDAY;
// 使用 switch 表达式,并将结果赋值给 typeOfDay 变量
String typeOfDay = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Weekday";
case SATURDAY, SUNDAY -> "Weekend";
};
System.out.println(day + " is a " + typeOfDay);
// 输出: WEDNESDAY is a Weekday
}
}
箭头 -> 语法
这是 switch 表达式最推荐的语法,箭头 -> 的右边是当 case 匹配时要执行的表达式或代码块。

- 如果右边是单个表达式(如上面的
"Weekday"),它会自动成为该case的返回值。 - 如果右边是代码块(用 包围),则必须使用
yield关键字来显式返回一个值。
示例(使用代码块和 yield):
Day day = Day.SATURDAY;
String typeOfDay = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
// 可以在这里执行多条语句
System.out.println("It's a weekday.");
yield "Weekday"; // 必须使用 yield 返回值
}
case SATURDAY, SUNDAY -> {
System.out.println("It's the weekend!");
yield "Weekend";
}
};
System.out.println(typeOfDay);
// 输出:
// It's the weekend!
// Weekend
yield 关键字
yield 用于在 switch 表达式的代码块中返回一个值,它类似于 return,但只作用于 switch 表达式内部,使用 yield 可以确保每个 case 都有明确的返回值,从而避免“贯穿”。
多常量标签
在传统的 switch 语句中,如果想为多个 case 执行相同的操作,需要重复写 case 标签或利用“贯穿”。switch 表达式简化了这一点,可以用逗号 将多个常量放在同一个 case 中。
// 上面的例子已经展示了这一点 case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Weekday";
default
default 标签和 case 标签的用法完全一样,可以返回一个值。
int errorCode = 404;
String errorMessage = switch (errorCode) {
case 200 -> "OK";
case 404 -> "Not Found";
case 500 -> "Internal Server Error";
default -> {
System.out.println("Unknown error code: " + errorCode);
yield "Unknown Error";
}
};
switch 表达式 vs. switch 语句(传统)
特性
switch 表达式 (Java 12+)
switch 语句 (Java 11及以前)
目的
计算并返回一个值
执行一个操作块
返回值
可以,通过赋值给变量
不可以,没有返回值
语法
使用 -> 或
只能使用
break
不需要,也不允许(在 -> 语法中)
必须,否则会“贯穿”
yield
在代码块中用于返回值
不存在
多常量
支持,用逗号分隔
支持,但需要重复写 case 或利用“贯穿”
典型用法
String result = switch (...) { ... };
switch (...) { ... }
完整示例与最佳实践
假设我们要根据成绩等级计算绩点。
public class SwitchExpressionBestPractice {
public static void main(String[] args) {
char grade = 'B';
// 使用 switch 表达式
double gpa = switch (grade) {
case 'A' -> 4.0;
case 'B' -> 3.0;
case 'C' -> 2.0;
case 'D' -> 1.0;
case 'F' -> 0.0;
default -> {
// 处理无效输入
System.err.println("Invalid grade: " + grade);
yield -1.0; // 返回一个错误码
}
};
if (gpa >= 0) {
System.out.println("The GPA for grade " + grade + " is " + gpa);
} else {
System.out.println("Could not calculate GPA.");
}
// 输出: The GPA for grade B is 3.0
}
}
switch 表达式是 Java 语言的一次重要进化,它使得代码更加:
- 简洁:用一行代码就能完成条件判断和赋值。
- 安全:从语法层面杜绝了“贯穿”这一经典错误。
- 强大:
switch 不再仅仅是流程控制语句,更是一个功能完备的表达式,可以无缝集成到任何需要表达式的地方。
建议:从 Java 12 开始,只要条件允许,优先使用 switch 表达式,而不是传统的 switch 语句,只有在需要执行复杂的、没有返回值的操作序列时,才考虑使用传统的 switch 语句。
default 标签和 case 标签的用法完全一样,可以返回一个值。
int errorCode = 404;
String errorMessage = switch (errorCode) {
case 200 -> "OK";
case 404 -> "Not Found";
case 500 -> "Internal Server Error";
default -> {
System.out.println("Unknown error code: " + errorCode);
yield "Unknown Error";
}
};
switch 表达式 vs. switch 语句(传统)
| 特性 | switch 表达式 (Java 12+) |
switch 语句 (Java 11及以前) |
|---|---|---|
| 目的 | 计算并返回一个值 | 执行一个操作块 |
| 返回值 | 可以,通过赋值给变量 | 不可以,没有返回值 |
| 语法 | 使用 -> 或 |
只能使用 |
break |
不需要,也不允许(在 -> 语法中) |
必须,否则会“贯穿” |
yield |
在代码块中用于返回值 | 不存在 |
| 多常量 | 支持,用逗号分隔 | 支持,但需要重复写 case 或利用“贯穿” |
| 典型用法 | String result = switch (...) { ... }; |
switch (...) { ... } |
完整示例与最佳实践
假设我们要根据成绩等级计算绩点。
public class SwitchExpressionBestPractice {
public static void main(String[] args) {
char grade = 'B';
// 使用 switch 表达式
double gpa = switch (grade) {
case 'A' -> 4.0;
case 'B' -> 3.0;
case 'C' -> 2.0;
case 'D' -> 1.0;
case 'F' -> 0.0;
default -> {
// 处理无效输入
System.err.println("Invalid grade: " + grade);
yield -1.0; // 返回一个错误码
}
};
if (gpa >= 0) {
System.out.println("The GPA for grade " + grade + " is " + gpa);
} else {
System.out.println("Could not calculate GPA.");
}
// 输出: The GPA for grade B is 3.0
}
}
switch 表达式是 Java 语言的一次重要进化,它使得代码更加:
- 简洁:用一行代码就能完成条件判断和赋值。
- 安全:从语法层面杜绝了“贯穿”这一经典错误。
- 强大:
switch不再仅仅是流程控制语句,更是一个功能完备的表达式,可以无缝集成到任何需要表达式的地方。
建议:从 Java 12 开始,只要条件允许,优先使用 switch 表达式,而不是传统的 switch 语句,只有在需要执行复杂的、没有返回值的操作序列时,才考虑使用传统的 switch 语句。
