Java 14前switch仅支持byte、short、char、int、enum、String;long、boolean、Double等不支持,String需Java 7+,Java 14+支持sealed类和record的模式匹配,switch表达式需用->和yield,Android需注意D8优化影响。

Java 14 之前 switch 只支持 byte、short、char、int、enum 和 String
这是最常被查错的地方:很多人以为 long 能用,结果编译直接报 error: incompatible types: long cannot be converted to int。本质是 JVM 的 tableswitch 和 lookupswitch 字节码指令只接受 32 位及以下整型或引用类型(String 是特例,JVM 7+ 加入支持)。boolean 也不行——哪怕它逻辑上只有两个值,但没被纳入语言规范。
实操建议:
立即学习“Java免费学习笔记(深入)”;
-
long值想进 switch?先转成int或String,但要注意溢出风险;更稳妥的是改用if-else -
Double、Float等包装类不能直接用,会触发 NPE 或编译失败;必须拆箱再判断,但浮点数本身就不适合精确匹配,别硬塞进 switch -
String在 Java 7+ 才支持,如果项目还在用 Java 6,连"a"都会报错
Java 14+ 支持 sealed 类和 record 的 switch 模式匹配(需开启预览特性)
这不是“加了个新类型”,而是彻底改变了 switch 的语义:从值匹配升级为类型 + 结构匹配。比如你有一个密封类 Shape,子类是 Circle、Rectangle,就能写 case Circle c -> c.radius 这种带变量绑定的分支。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 必须加编译参数:
--enable-preview --source 14(后续版本对应升级,如 Java 17 用--source 17) - 运行时也要加
--enable-preview,否则UnsupportedOperationException直接抛给你 -
record能用,但普通class不行——除非它显式声明为sealed并允许你穷举所有子类 - IDE 可能不识别新语法,别急着删红波浪线,先确认 JDK 和语言级别设置是否对齐
switch 表达式(Java 12+)和传统语句的关键区别在 break 和返回值
老写法里漏个 break 就掉到下一个 case,新表达式用 -> 替代 :,自动终止,不穿透。更重要的是:它是个表达式,有明确类型,可以赋值给变量或直接 return。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 旧代码迁移到
->时,别把break value;直接改成-> value;——前者是语句,后者是表达式,混用会编译失败 - 多个语句要用
{}包裹,并显式写yield value;,不是return,也不是break - 类型推断很严格:所有分支返回类型必须一致,
case 1 -> "a"和case 2 -> 42会报错,因为 String 和 Integer 无法统一为同一类型
Android 开发者特别注意:D8/R8 对 switch 的优化可能隐藏兼容性问题
AGP 4.2+ 默认启用 D8 编译器,它会把某些 switch 编译成 if-else 或查找表,尤其对 String 和稀疏枚举。看起来功能正常,但如果你在反射中检查字节码结构,或依赖某个 case 的执行顺序做 hack,就可能翻车。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 不要在
switch (Build.VERSION.SDK_INT)中依赖 case 排序做范围判断,D8 可能重排;改用 if-else 更可控 - 混淆后
enum名称可能被压缩,但 switch 内部仍靠 ordinal 匹配——只要没手动调ordinal()或序列化,一般没事 - 如果发现某台 Android 5.0 设备上 switch 没走对分支,优先检查是否用了 Java 8+ 的
Stringswitch,而 minSdkVersion 设得太低
真正容易被忽略的,是不同 JDK 版本下 switch 字节码生成策略的差异——它不改变语法行为,但会影响性能临界点和反编译可读性。别只盯着能不能用,得看实际跑起来是不是你预期的样子。









