Skip to main content

JEP 532:模式、instanceof 与 switch 中的原始类型(第五次预览)

引言

自 JDK 16 起,Java 的模式匹配一路演进,逐渐长成了一套强大而优雅的语言机制。但它始终缺着一块拼图——原始类型。JEP 532 补上了这最后一块,让模式匹配从"只服务于引用类型"变成了一套真正覆盖所有 Java 类型的统一系统。而它这么做的方式,还顺手消灭了一整类隐蔽的精度丢失 bug。

模式匹配缺的那块拼图

Java 的模式匹配从 JDK 16 引入 instanceof 模式开始,一路演进:类型模式、记录模式(record patterns)、switch 模式……一步步变得越来越强大。但这套体系里始终有一块显眼的空白——原始类型

  • 类型模式、记录模式和 switch 模式,全都只覆盖引用类型
  • 原始类型被完全排除在外:没有 instanceof int,也没有 case int i
  • 更别扭的是,记录中原始类型的组件无法被精确匹配。当你解构一个含 int 字段的 record 时,模式匹配帮不上忙。

结果就是:只要场景一涉及数值,开发者就被迫回到老路子——手写范围检查、手动强制类型转换。模式匹配本该带来的简洁,在数值代码里荡然无存,取而代之的是散落各处的 cast 和 if 判断。

这个 JEP 带来了什么

JEP 532 把原始类型正式补进了模式匹配的版图,让它成为一套完整的系统:

  • 凡是允许写模式的地方,都可以写原始类型模式。
  • instanceof 可以对原始类型使用,成为一种基于值的安全检查。
  • switch 支持任意原始类型,包括 longfloatdoubleboolean——不再局限于以往的 intString
  • 记录解构可以直接绑定原始类型的组件。

从此,模式匹配不再是引用类型的专属工具,而是一套引用类型与原始类型通用的统一语言。

核心概念:精确性(exactness)

这个特性的整个设计,都围绕着一个核心概念——精确性(exactness)

当你写 x instanceof byte b 时,编译器检查的不是简单地"把值截断成 byte",而是问一个更严肃的问题:这个值能否无损地放进一个 byte?

  • **无信息损失的扩宽(widening)会成功。**比如把一个能装进 byte 的值匹配为 byte。
  • **会丢精度的收窄(narrowing)则匹配失败。**如果一个值超出了 byte 的表示范围,匹配直接不成立。

这个设计的精妙之处在于:它把以前悄悄发生的类型转换,变成了显式且可检查的操作。过去一次写错的强制转换会静默地丢掉高位、损失精度,而且编译器不会给你任何警告;现在,同样的情况会变成一次干净利落的"匹配失败",而不是一个潜伏在代码深处的 bug。

值得一提的是,无条件精确的转换依旧会编译成一次普通的扩宽,不会引入任何额外开销。精确性检查只在真正可能有损失的地方才起作用。

代码示例

switch 支持原始类型:

// switch over long
String classify(long v) {
return switch (v) {
case 0L -> "zero";
case long pos if pos > 0 -> "positive";
default -> "negative";
};
}

// instanceof with primitives
if (x instanceof byte b) {
// x fits in a byte without loss
}

第一个例子对一个 longswitch——这在以前是根本不允许的。它还用上了带守卫(guard)的模式 case long pos if pos > 0

第二个例子用 instanceof 检查一个值能否无损地放进 byte。这不是一次简单的类型判断,而是一次值域层面的精确检查:只有当 x 确实落在 byte 的范围内时,分支才会进入。

前后对比

此前:

  • 每次收窄转换前,都要手写范围检查
  • switch 只能用于类 int 的类型,以及 String 和枚举。
  • 转换一旦写错,就会悄无声息地丢失精度,编译器帮不了你。

此后:

  • 所有类型共用一套统一的模式语言。
  • switch 可以直接写 longdoubleboolean 等任意原始类型。
  • 有损转换变成匹配失败,而不是潜伏的 bug。

预览状态

这已经是第五次预览了,一个很有分量的信号——它意味着 API 设计已经相当稳定、离正式转正应该不远了。

  • 它在 JDK 27 中作为第五次预览发布,延续了 JDK 26 的语言设计。
  • 编译和运行时都需要 --enable-preview 标志。
  • 它属于 Project Amber 的一部分,与我们已经熟悉的记录类型(records)、密封类型(sealed types)一脉相承。

结论

JEP 532 让模式匹配终于覆盖了所有 Java 类型。一套匹配模型,引用类型和原始类型通用;代码不仅更简洁,也因为"精确性"的引入而更安全。它补上的不只是一块语法拼图,更是把一整类静默的精度丢失 bug,转化成了编译期或运行期可见的"匹配失败"。