Java开关案例

wen java案例 1

Java switch-case 终极指南:从基础语法到模式匹配的演进


目录导读

  1. 传统 switch-case 的语法与陷阱
  2. Java 12+ 的箭头语法(->)与表达式
  3. Java 17+ 的模式匹配与 null 安全
  4. switch 与 if-else 的性能与可读性博弈
  5. 实战案例:状态机与策略模式重构
  6. 常见问题 Q&A(含面试高频题)

传统 switch-case 的语法与陷阱

在 Java 8 及之前,switch 只能用于 intcharString 和枚举类型,经典语法如下:

Java开关案例

switch (day) {
    case MONDAY:
        System.out.println("工作日");
        break;
    case SATURDAY:
    case SUNDAY:
        System.out.println("周末");
        break;
    default:
        System.out.println("非法输入");
}

三个致命陷阱

  • 忘记 break 导致穿透(fall-through)——虽然有时刻意利用,但多数是 BUG 源头。
  • 作用域冲突:所有 case 共享同一作用域,同名变量会编译报错。
  • String 的 equals 隐式比较:底层虚拟机会调用 hashCode() + equals() 优化,但 null 值会抛 NPE。

Java 12+ 的箭头语法(->)与表达式

Java 12 引入 -> 语法,支持无穿透表达式返回值

int num = switch (day) {
    case MONDAY -> 1;
    case TUESDAY, WEDNESDAY -> 2;
    default -> 0;
};

关键改进

  • 每个分支自动 break,不再需要写 break
  • 多值用逗号合并(如 case TUESDAY, WEDNESDAY)。
  • 可以作为表达式赋值,配合 yield 返回复杂逻辑:
int result = switch (num) {
    case 1 -> 10;
    case 2 -> {
        int temp = num * 5;
        yield temp + 1;
    }
    default -> -1;
};

Java 17+ 的模式匹配与 null 安全

这是 switch 的史诗级升级(JEP 406、420、427),现在可以直接匹配类型和记录:

Object obj = getObject();
String result = switch (obj) {
    case Integer i -> "整数: " + i;
    case Long l -> "长整: " + l;
    case String s && s.length() > 3 -> "长字符串: " + s;
    default -> "未知类型";
};

重点特性

  • 类型守卫case String s && s.length() > 3 支持条件筛选。
  • null 安全:可以显式处理 case null ->,不再 NPE。
  • 记录解构(Java 21 预览):case Point(int x, int y) -> x + y

switch 与 if-else 的性能与可读性博弈

性能层面

  • 传统 switch 对于 int 枚举使用 tableswitch(跳转表)或 lookupswitch(二分查找),时间复杂度 O(1) 或 O(log n)。
  • 箭头语法与 if-else 编译后字节码差异不大,但可读性碾压。
  • 推荐:分支 ≥ 5 且条件固定,用 switch;分支少或动态条件,用 if-else。

可读性设计

// 反例:多层 if 金字塔
if (status == 1) {
    if (type == 'A') { ... }
} else if (status == 2) { ... }
// 正例:switch 扁平化
switch (status) {
    case 1 -> handleStatusOne(type);
    case 2 -> handleStatusTwo();
}

实战案例:状态机与策略模式重构

场景:订单状态流转(待支付、已支付、已发货、已完成)。

enum OrderState {
    PENDING_PAYMENT, PAID, SHIPPED, COMPLETED
}
String applyEvent(OrderState current, Event event) {
    return switch (current) {
        case PENDING_PAYMENT -> switch (event) {
            case PAY -> "PAID";
            case CANCEL -> "CANCELLED";
            default -> "非法操作";
        };
        case PAID -> switch (event) {
            case SHIP -> "SHIPPED";
            default -> "非法操作";
        };
        case SHIPPED -> switch (event) {
            case COMPLETE -> "COMPLETED";
            default -> "非法操作";
        };
        case COMPLETED -> "终态不可变更";
    };
}

策略模式优化:通过 switch 返回 Function 或 Lambda 实现算法映射。


常见问题 Q&A(含面试高频题)

Q1:switch 能否用 long 或 double 作条件?
不能,只支持 intcharshortbyteStringEnumvar(推断为这些类型)。

Q2:箭头语法和传统冒号语法能混用吗?
不能,同一 switch 内必须统一语法,否则编译报错。

Q3:case null 在旧版 Java 如何安全处理?

if (obj == null) { ... } else {
    switch (obj) { ... }
}

Java 17+ 可直接 case null ->

Q4:yield 与 return 有什么区别?

  • return 跳出整个方法,yield 仅跳出 switch 并返回一个值。
  • yield 只能在 switch 表达式内使用,且必须赋值给变量或作为返回值。

Q5:模式匹配中 case String scase String s && s.length() > 3 的顺序重要吗?
重要,Java 会从上到下匹配,一旦命中即结束,所以更具体的条件应放在前面。


Java 的 switch 已从“简单分支工具”进化为“模式匹配利器”,建议开发者拥抱新语法,但注意团队代码规范(如 Java 11 项目勿用箭头语法)。选择策略:项目使用 17+,用模式匹配;否则用传统语法搭配 default 分支兜底。

互动提问:你在重构旧代码时,遇到过哪些 switch 相关的“谜之穿透”问题?欢迎在评论区分享你的坑位。

抱歉,评论功能暂时关闭!