Skip to content

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 的区别

特性传统 switchswitch 表达式
返回值
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 使用,编译器能确保穷尽性检查,代码更安全。

基于 VitePress 构建