switch 学会了按类型和 record 结构匹配。null 怎么处理?顺序和守卫怎么算?哪些写法会被编译器拒绝?这篇逐项真实编译、运行,并看字节码。
传统 switch(String) 遇到 null → NullPointerException 模式 switch 没有 case null,遇到 null → NullPointerException 写了 case null:→ case null 分支 case null, default:→ null 与 default 合并 Integer 42 经过三个 Integer 分支(大 / 中 / 小):→ 中 对 Integer 的常量 switch,遇到 null → NullPointerException
三个 when 守卫依次求值:结果 B,守卫被求值的次数 = 2(命中第二个后,第三个不再求值) 守卫只对类型匹配的分支求值:结果 s2,求值次数 = 2(Integer 分支类型不符,守卫没有执行) 按类型分派:Integer String Double Char List int[] null
eval(Add(Num 2, Mul(Num 3, Num 4))) = 14;eval(Neg(Mul(Add(Num 1,Num 2), Num 5))) = -15 record 模式里访问器抛出异常 → MatchException: java.lang.IllegalStateException: accessor boom;cause = java.lang.IllegalStateException: accessor boom 嵌套 record 模式,Add(Num 1, null):→ 右边不是 Num 但是 Expr(右子模式 Expr y 能匹配 null) Add(Num 1, null) 对 (Num x, Num y)(null 不匹配类型模式 Num)再对 (var x, var y):→ B
后面的分支被前面的类型模式支配 → this case label is dominated by a preceding case label
带守卫的分支放在无守卫之前(合法) → 编译通过
无守卫分支放在带守卫之前(被支配) → this case label is dominated by a preceding case label
Object 上没有 default → the switch expression does not cover all possible input values
sealed 缺一个子类 → the switch expression does not cover all possible input values
sealed 全覆盖,没有 default → 编译通过;运行:2
default 放在中间,后面还有类型分支 → this case label is dominated by a preceding case label
分支里 fall-through(用 case ...: 旧语法穿透到有绑定变量的分支) → illegal fall-through to a pattern
同一个 case 里 `case String s, Integer i`(多个模式) → illegal fall-through from a pattern
字节码里与 typeSwitch 有关的行:
#13 = InvokeDynamic #0:#14 // #0:typeSwitch:(Ljava/lang/Object;I)I
#14 = NameAndType #15:#16 // typeSwitch:(Ljava/lang/Object;I)I
#15 = Utf8 typeSwitch
BootstrapMethods:
BootstrapMethods
#61 = MethodHandle 6:#62 // REF_invokeStatic java/lang/runtime/SwitchBootstraps.typeSwitch:(Ljava/lang/invoke/MethodHandles$Lookup;Ljav
#62 = Methodref #63.#64 // java/lang/runtime/SwitchBootstraps.typeSwitch:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Lja
#63 = Class #65 // java/lang/runtime/SwitchBootstraps
#64 = NameAndType #15:#66 // typeSwitch:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/la
#65 = Utf8 java/lang/runtime/SwitchBootstraps