Java 17+ switch模式匹配需显式启用--enable-preview,类型模式(如case String s:)仅匹配非null且可安全转换的值,null和不兼容类型均跳过;record嵌套模式需Java 20+且类型均为sealed或record;各分支返回类型须统一,否则推导失败。

Java 17+ switch 表达式怎么用模式匹配?
Java 17 开始,switch 表达式支持模式匹配(预览特性),但默认不启用,必须显式开启。它不是“自动升级”的语法糖,而是需要编译器、运行时和明确的语法配合才能生效。
核心限制:模式匹配是预览特性,每次编译和运行都得加参数,否则编译失败或报错 Incompatible types: cannot convert from Object to String 这类看似奇怪的类型错误。
- 编译时加
--enable-preview --source 17(或更高版本,如--source 21) - 运行时也必须加
--enable-preview,缺一不可 - IDE(如 IntelliJ)需在项目 SDK 和编译器设置里同步开启预览特性,否则编辑器会标红,但实际编译可能通过
switch 中的类型模式(case String s:)为什么有时不进分支?
类型模式只在值非 null 且可安全强制转换时才匹配。它不是“类型检查 + 赋值”,而是“类型检查 + 解构绑定”,一旦类型不兼容或为 null,直接跳过该 case,不会抛异常,也不会 fallback 到 default —— 除非你写了 default,否则可能静默漏处理。
-
null值永远不会匹配任何类型模式,例如case String s:对null完全不响应 - 如果对象是
StringBuilder,写case String s:也不匹配,哪怕重写了toString() - 推荐总是配一个
default分支兜底,或单独处理null:case null:(Java 21 正式支持,17–20 需用预览)
Object obj = getUnknown();
String result = switch (obj) {
case String s -> "str:" + s.length();
case Integer i -> "int:" + i;
case null -> "got null";
default -> "other: " + obj.getClass();
};
record 模式(case Point(int x, int y):)能嵌套吗?
可以,但嵌套深度受编译器限制,且所有中间类型都必须是 sealed 或 record,否则编译报错 Pattern is not supported in this context。这不是运行时限制,而是语义校验 —— JVM 要确保所有分支路径可静态穷举。
立即学习“Java免费学习笔记(深入)”;
- 嵌套 record 模式要求被匹配的对象是
record,且字段类型也支持模式(如也是record或基础类型) - 不能对普通 class 使用字段解构,即使它有 getter;必须是
record或显式声明的sealed层级 - Java 17 的预览版不支持嵌套 record 模式,要到 Java 20+(仍预览)才逐步放开
示例(Java 21):
record Point(int x, int y) {}
record Circle(Point center, double r) {}
Object shape = new Circle(new Point(1, 2), 3.0);
String desc = switch (shape) {
case Circle(Point(int x, int y), double r) ->
String.format("circle at (%d,%d), r=%.1f", x, y, r);
default -> "unknown";
};
为什么 switch 表达式返回值类型推导失败?
模式匹配下,每个 case 分支的表达式类型必须能统一为一个公共父类型,否则编译器无法推导返回值类型,报错类似 Type mismatch: cannot convert from String to Number。这不是 bug,是类型系统在强制你显式收敛。
- 所有分支返回值类型不一致时,JVM 不会自动向上转成
Object,必须手动 cast 或用三元、临时变量绕开 - 避免混用原始类型和包装类(如
case Integer i -> ivscase String s -> s.length()),前者是Integer,后者是int,类型不兼容 - 最稳妥做法:显式声明目标类型,或用
var+ 统一分支返回类型(比如全返回String)
容易被忽略的一点:预览特性下,IDE 的类型推导可能滞后或误报,别全信红色波浪线,以 javac 实际输出为准。


















