Java SE 14(于 2020 年 3 月发布)引入了一种模式匹配作为预览特性,将成为Java SE 16(将于 2021 年 3 月发布)的一项永久性特性。
模式匹配的第一阶段仅限于一种模式(类型模式)和一种语言构造(instanceof),但这只是整个完整特性的第一部分。
简单地说,模式匹配可以帮我们减少繁琐的条件状态提取。在进行条件状态提取时,我们问一个与某个对象有关的问题(比如“你是 Foo 吗”),如果答案是肯定的,我们就从对象中提取状态:“if (x instanceof Integer i) { … }”,其中 i 是绑定变量。
使用 instanceof 获取对象类型是一种条件提取形式,在获得到对象类型之后,总是要将对象强制转换为该类型。
我们可以在 java.util.EnumMap 的复制构造函数中看到一个典型的例子:
public EnumMap(Map<K, ? extends V> m) {
if (m instanceof EnumMap) {
EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
// optimized copy of map state from em
} else {
// insert elements one by one
}
}
构造函数接收另一个 Map 作为参数,它可能是也可能不是一个 EnumMap。如果是的话,构造函数可以将其强制转换为 EnumMap,并使用更有效的方法复制 Map 的状态,否则的话,它将使用一般的插入方式。
这种“测试并进行强制转换”的习惯用法是多余的吗?在有了 m instanceof EnumMap 之后,我们还可以做些什么?模式匹配可以将测试和强制转换合并到单个操作中。类型模式将类型名称与绑定变量的声明组合在一起,如果 instanceof 成功,绑定变量将被绑定到对象的窄化类型:
public EnumMap(Map<K, ? extends V> m) {
if (m instanceof EnumMap<K, ? extends V> em) {
// optimized copy of map state from em
} else {
// insert elements one by one
}
}
在上面的例子中,EnumMap<K, ? extends V> em 是一种类型模式(看起来像是一种变量声明)。我们扩展了 instanceof,让它可以接受模式和普通类型。我们先测试 m 是不是一个 EnumMap,如果是,则将其转换为 EnumMap,并将结果绑定到 if 语句第一行中的 em 变量。
在 instanceof 之后必须进行显式的类型转换,这是一种繁琐的操作,而融合这些操作的好处不仅仅是为了简洁(尽管简洁是美好的),它还消除了一个常见的错误来源。在剪切和粘贴 instanceof 及强制转换代码,容易在修改了 instanceof 的类型之后忘记修改强制转换类型,这就给了漏洞一个藏身之处。通过消除这个问题,我们可以消灭所有这种类型的 bug。
另一个需要经常进行“测试后强制转换”的地方是在实现 Object::equals 时。IDE 可能会为 Point 类生成 equals()方法:
public boolean equals(Object o) {
if (!(o instanceof Point))
return false;
Point p = (Point) o;
return x == p.x && y == p.y;
}
下面是使用模式匹配的等效代码:
public boolean equals(Object o)
Java SE 16 引入的模式匹配特性通过结合测试和强制转换,有效减少了代码中的繁琐操作,如 instanceof 后的强制类型转换。这一特性最初在 Java 14 作为预览特性推出,旨在提高代码的简洁性和安全性。本文深入探讨了模式匹配的使用,包括类型模式、绑定变量的作用域和流式作用域,以及未来可能的应用,如在 switch 语句中的支持和与 Record、封印类的协同工作,有望引领一个更加“对称”的 API 设计时代。
最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



