提到模式匹配(Pattern Matching),Java 开发人员可能会比较陌生。实际上,其他编程语言的开发人员早就已经使用过模式匹配了。JVM 上的编程语言 Scala 的模式匹配功能就很强大。
什么是模式匹配?
为了更好地解释模式匹配,我们从一个简单的例子开始。我们希望创建一个方法,可以把任何对象转换成 String 格式。这就需要根据对象的类型来进行不同的格式化操作。我们可以很容易就写出下面这样的代码。这段代码的核心是使用 instanceof 操作符来检查输入对象的类型,再根据对象类型进行格式化操作。
public class ObjectFormatter {
public String format(Object input) {
if (input == null) {
return "";
} else if (input instanceof Number) {
return NumberFormat.getNumberInstance().format(input);
} else if (input instanceof LocalDateTime) {
return ((LocalDateTime) input).format(DateTimeFormatter.ISO_DATE_TIME);
} else {
return input.toString();
}
}
}
上述对 instanceof 操作符的使用就是模式匹配的一种简单形式。
一个模式由匹配 predicate 和模式变量的集合组成。
- 匹配 predicate 判断一个模式是否可以匹配目标对象。
- 如果模式匹配的话,模式变量的集合用来从目标对象中提取值。
在 instanceof 操作符的例子中,匹配 predicate 的作用是检查目标对象的类型,而模式变量的集合中只有一个变量,就是目标对象自身。这种类型的模式,被称为类型模式(type pattern)。除了类型模式之外,计划中的模式还包括记录类型模式和数组模式。
模式匹配是一个涵盖范围非常大的功能。根据现在 Java 的发布周期,模式匹配的内容会在不同的 Java 版本中逐渐添加进来。具体的发布周期可以参考下面的表格。这个表格的右侧三列表示的是不同的与模式匹配相关的功能,每一行表示这些功能在对应 Java 版本中的可用状态。
Java版本 | instanceof 模式 | switch 的模式匹配 | 记录类型模式 |
Java 14 | 预览 | ||
Java 15 | 二次预览 | ||
Java 16 | 正式功能 | ||
Java 17 | 正式功能 | 预览 | |
Java 18 | 正式功能 | 二次预览 | |
Java 19 | 正式功能 | 三次预览 | 预览 |
以 Java 17 为例,可以使用 instance 模式的正式功能,以及 switch 模式匹配的预览功能。
Java 18 和 Java 19 中可用的模式匹配功能也列在了表格中,作为参考。
instanceof 模式匹配
Java 中的 instanceof 操作符用来检查对象的类型。下面的代码给出了通常使用 instanceof 操作符的代码范式。在 if 语句中使用 instanceof 来进行检查,如果检查通过,则使用强制类型转换,把输入对象 obj 转换成 String 类型的 s,最后再使用变量 s。
if (obj instanceof String) {
String s = (String) obj;
}
从上述代码中可以看到,对 instanceof 操作符的使用范式是非常繁琐的,其中需要检查的目标类型 String 就出现了三次。在使用了 instanceof 模式匹配之后,代码可以简化很多。在下面的代码中, String s 表示类型模式,其中 String 是需要匹配的类型,s 是匹配成功之后用来捕获目标对象的变量。该变量 s 可以直接在 if 语句块中使用。