Switch 表达式
JDK 14 引入了 switch 表达式,JDK 17 成为正式特性。
switch 从单纯控制流变成了可以返回值的表达式。
传统 switch vs switch 表达式
传统 switch(语句)
java
switch (day) {
case MONDAY:
case FRIDAY:
System.out.println("Work");
break;
case SATURDAY:
case SUNDAY:
System.out.println("Rest");
break;
default:
System.out.println("Unknown");
}问题:
- 容易忘记
break,导致 fall-through bug - 每个 case 都要写
break,代码冗长 - 只能做语句,不能返回值
switch 表达式(返回值)
java
String result = switch (day) {
case MONDAY, FRIDAY -> "Work";
case SATURDAY, SUNDAY -> "Rest";
default -> "Unknown";
};好处:
- 箭头语法不会 fall-through
- 可以直接返回值
- 多值合并(逗号分隔)
基本语法
箭头语法
java
// 单值
case 值 -> 结果;
// 多值(逗号分隔)
case 值1, 值2, 值3 -> 结果;完整示例
java
import java.time.DayOfWeek;
public class SwitchExpressionDemo {
public static void main(String[] args) {
DayOfWeek day = DayOfWeek.FRIDAY;
// switch 表达式
String result = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "工作日";
case SATURDAY, SUNDAY -> "周末";
};
System.out.println(result); // 工作日
}
}多行代码块
箭头后可以是代码块:
java
String result = switch (day) {
case MONDAY -> {
System.out.println("Monday blues...");
yield "工作日"; // JDK 13+ 用 yield 返回值
}
case FRIDAY -> {
System.out.println("TGIF!");
yield "工作日";
}
default -> "其他";
};注意:
yield是 JDK 13+ 引入的,用于在代码块中返回值。之前用break with value(已废弃)。
与 sealed class 配合
switch 表达式和 sealed class 是绝配:
java
public sealed interface Shape permits Circle, Rectangle, Square {}
public record Circle(double radius) implements Shape {}
public record Rectangle(double width, double height) implements Shape {}
public record Square(double side) implements Shape {}
public class SealedSwitchDemo {
public static String describe(Shape shape) {
return switch (shape) {
case Circle c -> "圆形,半径=" + c.radius();
case Rectangle r -> "矩形,宽=" + r.width() + ",高=" + r.height();
case Square s -> "正方形,边长=" + s.side();
};
}
public static void main(String[] args) {
Shape c = new Circle(5.0);
Shape r = new Rectangle(3.0, 4.0);
Shape s = new Square(2.0);
System.out.println(describe(c)); // 圆形,半径=5.0
System.out.println(describe(r)); // 矩形,宽=3.0,高=4.0
System.out.println(describe(s)); // 正方形,边长=2.0
}
}编译器会检查是否穷尽了所有情况,漏掉会报错。
null 处理
JDK 21+ 支持在 switch 中处理 null:
java
// JDK 21+
String result = switch (str) {
case null -> "null 值";
case "hello" -> "问候语";
default -> "其他";
};JDK 17 之前需要先判断 null:
java
// JDK 17 及之前
String result;
if (str == null) {
result = "null 值";
} else {
result = switch (str) {
case "hello" -> "问候语";
default -> "其他";
};
}枚举类型
java
enum Color { RED, GREEN, BLUE }
public class EnumSwitchDemo {
public static String getColorName(Color color) {
return switch (color) {
case RED -> "红色";
case GREEN -> "绿色";
case BLUE -> "蓝色";
};
}
public static void main(String[] args) {
System.out.println(getColorName(Color.RED)); // 红色
System.out.println(getColorName(Color.GREEN)); // 绿色
}
}实际应用场景
场景一:计算器
java
public int calculate(int a, int b, String op) {
return switch (op) {
case "+" -> a + b;
case "-" -> a - b;
case "*" -> a * b;
case "/" -> b != 0 ? a / b : 0;
case "%" -> a % b;
default -> throw new IllegalArgumentException("Unknown operator: " + op);
};
}场景二:HTTP 状态码处理
java
public String handleStatusCode(int code) {
return switch (code) {
case 200 -> "OK";
case 201 -> "Created";
case 301 -> "Moved Permanently";
case 400 -> "Bad Request";
case 401 -> "Unauthorized";
case 403 -> "Forbidden";
case 404 -> "Not Found";
case 500 -> "Internal Server Error";
case 503 -> "Service Unavailable";
default -> "Unknown Status";
};
}场景三:消息路由
java
public void route(Message message) {
switch (message.getType()) {
case "TEXT" -> handleText(message);
case "IMAGE" -> handleImage(message);
case "VIDEO" -> handleVideo(message);
case "AUDIO" -> handleAudio(message);
case "FILE" -> handleFile(message);
}
}
private void handleText(Message m) { /* ... */ }
private void handleImage(Message m) { /* ... */ }
// ...与传统 switch 的区别
| 特性 | 传统 switch | switch 表达式 |
|---|---|---|
| 返回值 | ❌ | ✅ |
| fall-through | ✅(需 break) | ❌ |
| 多值合并 | case 值1: case 值2: | case 值1, 值2: |
| 代码块 | ✅ | ✅(用 yield 返回) |
| null 处理 | ❌ | JDK 21+ ✅ |
小结
switch 表达式让代码更简洁:
java
// ❌ 传统写法
switch (day) {
case MONDAY:
case FRIDAY:
result = "Work";
break;
// ...
}
// ✅ 表达式写法
String result = switch (day) {
case MONDAY, FRIDAY -> "Work";
case SATURDAY, SUNDAY -> "Rest";
default -> "Unknown";
};结合 sealed class 使用,编译器能确保穷尽性检查,代码更安全。
