守卫(when)、嵌套 record 模式、泛型 sealed 与枚举混合,让 switch 的规则变得复杂。哪些写法会被编译器拒绝?运行期的求值顺序和异常怎么表现?这篇用大量真实编译与运行逐条验证。
正常:case A a when a.x() > 0 -> 1; case A a -> 2; case B b -> 3 → 编译通过 只有带守卫的 A,没有无守卫的 A(不穷尽) → the switch expression does not cover all possible input values 无守卫的 A 在带守卫的 A 前面(被支配) → this case label is dominated by a preceding case label 守卫恒为 true(when true)后面再来无守卫的同类型 → this case label is dominated by a preceding case label 守卫里用绑定变量与 &&(s.length() 依赖 instanceof 绑定) → 编译通过 守卫里用 ||(绑定变量不一定存在) → 编译通过 守卫里的绑定变量用在 || 的右边 → cannot find symbol 守卫里修改绑定变量(s = "x") → cannot assign to s, as it was not declared inside the guard 守卫表达式不是 boolean(when 1) → incompatible types: int cannot be converted to boolean 守卫里调用抛受检异常的方法(没有 throws) → 编译通过 同一个 case 里用逗号写两个有绑定变量的模式 → illegal fall-through from a pattern case null, String s(null 与有绑定的模式合并) → invalid case label combination
Opt<T> 的 Some / None,带泛型的穷尽 switch → 编译通过 Opt<String> 上用 Some<Integer> 模式(类型参数不兼容) → incompatible types: Opt<String> cannot be converted to Some<Integer> Pair<Box<A>, Box<B>> 的嵌套 record 模式,穷尽 → 编译通过 嵌套模式缺一个组合(Box(A) 与 Box(A) 的组合没有覆盖 Box(B)) → the switch expression does not cover all possible input values record 模式的组件个数不对(Box(var a, var b)) → incorrect number of nested patterns record 模式里同名绑定变量重复(Pair(var x, var x)) → illegal attempt to redefine an existing match binding record 模式匹配 Box<S>(null 组件不匹配类型模式 A) → 编译通过 record 模式用 var 加守卫 case Box(var v) when v != null → 编译通过
sealed Shape2 的成员有枚举 Color:用 case Color.RED、case Color.GREEN、case Sq s → 编译通过 同上,缺少 Color.GREEN(不穷尽) → the switch expression does not cover all possible input values Color 常量在 Color 类型的 switch 里写成 case Color c when … → 编译通过 case RED(不限定)在 Shape2 的 switch 里 → cannot find symbol 常量标签 case 1 在 Integer 模式 case Integer i 之后 → this case label is dominated by a preceding case label 常量标签 case 1 在 case Integer i when … 之前 → 编译通过 字符串常量与 String 模式 → 编译通过
三个 A 分支的守卫依次求值:结果 mid,守卫调用 2 次(命中第二个后停止) 守卫里抛出的异常直接传播(不是 MatchException):StringIndexOutOfBoundsException: Index 10 out of bounds for length 4 没有 case null 时 switch(null) → NullPointerException case null -> 与 default 分开写:null 分支 Box(null) 对 case Box(A) 与 case Box(B)(没有全能分支)→ MatchException(null 组件不匹配类型模式,穷尽性要求兜底) Box(null) 加上 case Box<S>(var v) 全能分支:全能分支(v=null) 嵌套模式 Pair(A, B) 解构:A.x=1,B.s=z 守卫里重新引用 instanceof 绑定:偶数大于 10:42 1000 万次分派(6 种类型):模式 switch 89 ms;instanceof 链 34 ms(结果相同 true) JDK 21:守卫里调用 throws Exception 的方法,而 f 没有声明 throws:javac 编译通过;捕获到 java.lang.Exception: checked-from-guard JDK 27:守卫里调用 throws Exception 的方法,而 f 没有声明 throws:javac 编译通过;捕获到 java.lang.Exception: checked-from-guard