Java 17 switch模式匹配需启用预览特性(--enable-preview),仅支持switch表达式(→或: + yield),case String s: 同时完成类型检查与变量绑定,null需单独处理,不支持嵌套泛型,配合sealed class可实现编译期穷尽检查。

switch 表达式里怎么写模式匹配
Java 17 的 switch 模式匹配不是给所有类型默认开启的,得用预览特性(preview feature)才能用。不加 --enable-preview 编译或运行,会直接报错 error: pattern matching in switch is a preview feature。
实操建议:
- 编译时必须加
javac --enable-preview --source 17 MyTest.java - 运行时也得加
java --enable-preview MyTest,漏一个都不行 - 匹配对象类型时,
case A a:这种写法只在switch表达式(带->或:+yield)中有效,老式语句式switch(只有break)不支持 - 注意:模式变量
a的作用域仅限于对应case分支块内,不能跨 case 访问
为什么 instanceof + cast 被替换成 case String s:
以前写类型判断常这样:if (obj instanceof String) { String s = (String) obj; ... }。模式匹配把这俩动作合并了——case String s: 既做类型检查,又声明并初始化变量 s,不用再手动强转。
但要注意边界:
立即学习“Java免费学习笔记(深入)”;
-
case String s:只匹配非 null 的String,null 值不会进这个分支(除非显式写case null:) - 如果想同时处理
null和具体类型,得分开写:case null:和case String s:,顺序不能反,否则null会被前面的类型模式“吞掉”(实际不会,但逻辑上容易误判) - 不支持嵌套模式,比如
case List<string> list:</string>是非法的,JVM 层面擦除后无法运行时校验泛型
switch 模式匹配和传统 switch 在 return/yield 上的区别
模式匹配常用于表达式上下文(比如方法返回值),这时候必须保证每个分支都有明确结果,否则编译失败。
常见错误现象:error: missing yield statement 或 error: switch expression does not cover all possible input values。
实操建议:
- 用
->语法时,每个case后只能跟一个表达式或代码块,块里必须用yield返回值;别用return,那会直接退出方法 - 必须覆盖所有可能输入,包括
default(或穷举所有子类,若用 sealed class);漏掉default且类型不是enum或 sealed,编译不过 - 如果输入是
Object,光写case String s:和case Integer i:不够,还得加default:处理其他类型,否则编译报错
sealed class + switch 模式匹配才是完整闭环
单独用模式匹配类型只是“半自动”,真正减少 instanceof 泛滥、提升可维护性的场景,是配合 sealed class(Java 15+)使用。
比如定义 sealed interface Shape permits Circle, Rect {},那么 switch (shape) { case Circle c -> ...; case Rect r -> ...; } 就能被编译器确认穷尽,连 default 都不需要。
但容易踩的坑:
- 父类型必须显式声明
permits,子类必须用final、sealed或non-sealed之一修饰,否则编译报错 - IDE 可能不及时提示缺失分支,建议开编译器警告(
-Xlint:patternvalidation) - 运行时如果通过反射绕过 sealed 限制创建了新子类,switch 仍会进入
default(如果有),但编译期无法预警
模式匹配本身不难写,难的是设计好类型边界——sealed class 没配对,switch 就永远缺个 default;预览特性没开全,连编译都过不去。这些地方一卡住,就容易倒回去写一堆 instanceof。


















