可直接用switch表达式配合类型模式匹配替代if-else+instanceof+强制转换,JDK≥17且启用预览特性(JDK21起正式支持),case后写类型名自动完成类型检查与绑定,需显式处理null,支持when守卫条件,并与密封类结合实现编译期穷尽性检查。

可以直接用 switch 表达式配合类型模式匹配替代冗长的 if-else + instanceof + 强制转换组合,前提是 JDK 版本 ≥ 17 且未禁用预览特性(JDK 17 初始为预览功能,需显式启用;JDK 21 起已正式转正)。
case 后直接写类型名并绑定变量,自动完成 instanceof + 类型转换
这是最常用也最容易上手的用法。传统写法要先判断再强转,容易漏判或抛 ClassCastException;新模式把这两步合并进一个 case,安全又紧凑。
-
case String s ->:匹配String类型,并将值绑定到变量s,后续可直接使用s,无需(String)obj -
case Integer i ->:同理,i是已解包的int值(非Integer对象),可直接参与算术运算 - 不支持基本类型作为模式(如
case int i是非法的),只能是引用类型或null - 如果
switch表达式的 selector 是泛型类型(如Object),编译器会做类型擦除检查,但不会在运行时验证泛型实参
必须显式处理 null,否则编译报错
JDK 17 的模式匹配 switch 默认不再对 null “友好”——它不会自动跳到 default,也不会静默忽略。不写 case null 且 selector 可能为 null,编译直接失败。
- 正确写法:
case null -> "got null",单独分支处理 - 也可合并:
case null, default -> "null or unknown",但要注意语义是否合理 - 若你确定 selector 永远非空(比如来自密封类或严格校验后的输入),仍需写
case null -> throw new IllegalStateException()来满足穷尽性检查 - 这点和传统
switch(只接受常量)完全不同,是模式匹配强制要求的健壮性设计
用 when 添加守卫条件,避免嵌套 if
当单靠类型不够,还需额外逻辑判断(比如“是 String 且长度 > 5”),就用 when 子句。它只能跟在类型模式后,不能用于常量 case。
- 语法:
case String s when s.length() > 5 -> ... - 多个条件用
&&或||连接,但建议保持简单;复杂逻辑应提前提取方法,避免when变成隐藏的业务入口 -
when中的表达式在匹配类型成功后才执行,所以s已确保非null,无需再判空 - 注意:守卫条件不参与编译期穷尽性检查,所以即使写了
case String s when s.startsWith("A")和case String s,编译器仍认为所有String都被覆盖了
与密封类(sealed class)配合,实现真正意义上的穷尽分支
如果你的输入是自定义的密封类层次(如 sealed interface Shape permits Circle, Rectangle),模式匹配 switch 能在编译期确认是否覆盖全部子类型。
- 只要所有子类都被列为
case,且没写default,新增子类时编译直接报错:“non-exhaustive switch”,强迫你补全逻辑 - 此时
default不再是兜底项,而是反模式;应删掉,让编译器替你把关 - 若 selector 是密封类的父类型(如
Shape),case Circle c合法;但若 selector 是Object,就必须写case Circle c而不能只写case Circle(否则编译不过) - 这种组合是模式匹配最硬核的价值点:把运行时类型错误,提前锁死在编译阶段
真正难的不是写对语法,而是决定哪些类型该拆、哪些条件该放进 when、哪些该提前抽象成方法——模式匹配放大了设计选择的影响,写得越“顺”,越容易掩盖领域逻辑的模糊地带。


















