跳到主要内容

JEP 375:instanceof 的模式匹配(第二个预览版)

概括

通过运算符的_模式匹配_增强 Java 编程语言instanceof模式匹配允许更简洁、更安全地表达程序中的通用逻辑,即从对象中条件提取组件。这是JDK 15 中的预览语言功能。

历史

模式匹配由JEP 305instanceof于 2017 年中提出,并于 2019 年底作为预览语言功能针对 JDK 14 。此 JEP 建议在 JDK 15 中重新预览该功能,相对于 JDK 14 中的预览没有任何更改,以便收集更多反馈。

动机

几乎每个程序都包含某种逻辑,这些逻辑结合了测试表达式是否具有某种类型或结构,然后有条件地提取其状态的组成部分以进行进一步处理。例如,所有 Java 程序员都熟悉 instanceof-and-cast 习惯用法:

if (obj instanceof String) {
String s = (String) obj;
// use s
}

这里发生了三件事:测试(是objString)、转换(转换objString)以及新的局部变量 ( ) 的声明,s以便我们可以使用字符串值。这种模式很简单,所有 Java 程序员都可以理解,但由于多种原因,它并不是最理想的。这很乏味;不需要同时进行类型测试和强制类型转换(instanceof测试后您还会做什么?)。这个样板文件——特别是该类型的三次出现String——混淆了接下来的更重要的逻辑。但最重要的是,重复为错误在不被注意的情况下潜入程序提供了机会。

我们认为,Java 是时候拥抱模式匹配了,而不是寻求临时解决方案。模式匹配允许简洁地表达对象所需的“形状”(模式_)_,并允许各种语句和表达式根据其输入测试该“形状”(匹配)。从 Haskell 到 C#,许多语言都因其简洁性和安全性而采用了模式匹配。

描述

模式是 (1)可应用于目标的_谓词_和 (2)仅当谓词成功应用于目标时才从目标中提取的_一组__绑定变量_的组合。

类型_测试模式_由指定类型的谓词以及单个绑定变量组成。

运算instanceof符 ( JLS 15.20.2 ) 被扩展为采用类型测试模式而不仅仅是类型。在下面的代码中,该短语String s是类型测试模式:

if (obj instanceof String s) {
// can use s here
} else {
// can't use s here
}

运算instanceof符将目标obj与类型测试模式“匹配”,如下所示:如果obj是 的实例String,则将其强制转换为String并分配给绑定变量s。绑定变量在if语句的 true 块中,而不是在语句的 false 块中if

与局部变量的范围不同,绑定变量的范围由包含表达式和语句的语义确定。例如,在这段代码中:

if (!(obj instanceof String s)) {
.. s.contains(..) ..
} else {
.. s.contains(..) ..
}

true 块中的指s的是封闭类中的字段,sfalse 块中的 指的是运算符引入的绑定变量instanceof

当语句的条件if变得比单个条件更复杂时instanceof,绑定变量的范围也会相应地增长。例如,在这段代码中:

if (obj instanceof String s && s.length() > 5) {.. s.contains(..) ..}

绑定变量s位于运算符右侧的范围内&&,以及 true 块中。 (仅在成功时才计算右侧instanceof并将其分配给s。)另一方面,在此代码中:

if (obj instanceof String s || s.length() > 5) {.. s.contains(..) ..}

绑定变量s不在 || 右侧的范围内运算符,也不在 true 块的范围内。 (s此时指的是封闭类中的字段。)

instanceof当目标为空时,工作方式没有变化。也就是说,模式仅在不为空时才会匹配,并且s只会被分配。obj

使用模式匹配instanceof应该会显着减少 Java 程序中显式强制转换的总数。此外,类型测试模式在编写相等方法时特别有用。考虑以下取自《Effective Java》一书第 10 条的相等方法:

@Override public boolean equals(Object o) { 
return (o instanceof CaseInsensitiveString) &&
((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
}

使用类型测试模式意味着可以将其重写为更清晰的形式:

@Override public boolean equals(Object o) { 
return (o instanceof CaseInsensitiveString cis) &&
cis.s.equalsIgnoreCase(s);
}

语法相应instanceof 扩展:

RelationalExpression :
     ...
     RelationalExpression instanceof 参考类型
     RelationalExpression instanceof 模式

模式
     参考类型 标识符

未来的工作

未来的 JEP 将通过其他语言结构(例如switch表达式和语句)的模式匹配来增强 Java 编程语言。

备择方案

类型测试模式的好处可以通过语句中的_流类型_if或_类型切换_构造来获得。模式匹配概括了这两种结构。