JEP 305:instanceof的模式匹配(预览)
原文:https://openjdk.org/jeps/305
翻译:张欢
用instanceof
运算符的模式匹配来增强Java编程语言。模式匹配使程序中的通用逻辑,即从对象中有条件地提取组件,得以更简洁、更安全地表示。这是JDK 14的一个预览语言特性。
动机
几乎每个程序都包含某种逻辑,结合了对表达式的类型或结构的测试,然后有条件地提取其中的状态组件以进行进一步处理。例如,所有Java程序员都熟悉“先instanceof再转换”的习惯用法:
这里发生了三件事情:一个测试(obj
是不是一个String
),一个转换(将obj
转换为String
),和定义一个新的局部变量(s
)以便我们可以使用字符串的值。这种模式很简单,并且所有Java程序员都可以理解,但是由于一些原因,这不是最优的。这很乏味:应该没有必要既做类型测试,同时又做类型转换(你还能在instanceof
测试之后做什么其他的呢?)。这些样板代码——特别是出现了三次的String
类型——混淆了后面更重要的逻辑。但最重要的是,重复代码为错误提供了机会且不易被察觉。
与寻求特定的解决方案相比,我们相信是时候让Java拥抱模式匹配了。模式匹配允许简洁地表达对象所需的“形态”(模式),并允许各种语句和表达式针对其输入来测试“形态”(匹配)。从Hashkell到C#,许多语言都出于其简洁性和安全性而拥抱了模式匹配。
描述
模式是二者的组合:(1)可以应用于目标的谓词;(2)仅在谓词成功应用于目标时才从目标中提取的一组绑定变量。
类型测试模式由指定类型的谓词和单个绑定变量组合。
扩展instanceof
运算符(JLS 15.20.2)以采用类型测试模式,而不仅仅是类型。在下面的代码中,短语String s
就是类型测试模式:
instanceof
运算符将目标obj
与类型测试模式相“匹配”:如果obj
是String
的实例,那就将其转换为String
并赋值给绑定变量s
。绑定变量的作用域是if
语句的true代码块,而不是if
语句的false代码块。
与局部变量的作用域不同,绑定变量的作用域由包含的表达式和语句的语义确定。例如,在这样的代码中:
true代码块中的s
引用封闭类中的字段,false代码块中的s
引用由instanceof
运算符引入的绑定变量。
当if
语句的条件变得比单个instanceof
更复杂时,绑定变量的范围也会相应地增长。例如,在这样的代码中:
绑定变量s
的作用域既是&&
运算符的右边范围,同时也是true代码块范围。(右边范围只会在instanceof
成功时运算并赋值给s
。)另外,在这样的代码中:
绑定变量s
的作用域既不是||
运算符的右边范围,同时也不是true代码块范围。(此例中的s
引用封闭类型中的字段。)
当目标是null
时instanceof
的工作方式不变。即,只有obj
不是null
时,模式才会匹配,s
才会被赋值。
在instanceof
中使用模式匹配应该会大大减少Java中显式强制转换的总数。此外,类型测试模式在编写equals
方法时特别有用。考虑下面选择《Effective Java》书中第10条的equals
方法:
使用类型测试模式意味着这可以重新写成更清楚的样子:
instanceof
的语法被相应地扩展:
未来的工作
未来的JEP将通过与其他语言结构,如switch
表达式和语句,进行模式匹配来增强Java编程语言。
备选方案
类型测试模式的好处可以通过if
语句中的的流程类型或类型switch结构中获得。模式匹配涵盖了这两种结构。
依赖
实现可能用到JEP 309(动态Class文件常量)。