if (obj instanceof String s) {
System.out.println(s.toUpperCase());
}
模式变量使用的是流作用域(flow scoping)。一个模式变量能够出现在作用域中,当且仅当编译器可以推断出模式匹配必定成功,并且该变量被赋予了一个值时。在上面的例子中,if 语句块的代码只有在模式匹配成功了之后才会执行,变量 s 此时必定被赋予了值 obj,因此编译器可以确定 s 必定在 if 语句块的作用域中。
关于流作用域,其实不用了解太多。如果使用错误,编译器会提示你的。
下面的代码给出了 instanceof 模式匹配的代码示例。第一个 if 匹配 String 类型的同时,加上了对字符串长度的检查;第二个 if 匹配剩下的 String 类型的对象。在第一个 if 的条件中,obj instanceof String s 和 s.length() > 10 的顺序不能反过来。这里利用了 && 的短路(short-circuit)特性,当第一个 instanceof 模式匹配成功之后,才会执行后面的判断,这个时候 s 必然是一个 String 对象,可以安全地使用 length 方法;如果第一个 instanceof 模式不匹配,后面的判断不会被执行,因此也不会出现错误。
public class StringMatch {
public void test(Object obj) {
if (obj instanceof String s && s.length() > 10) {
System.out.println("长字符串 -> " + s);
} else if (obj instanceof String s) {
System.out.println("短字符串 -> " + s);
} else {
System.out.println("其他");
}
}
}
在 switch 语句和表达式中使用模式匹配
在 Java 17 中,switch 语句和表达式的 case 子句中可以使用模式匹配。该功能在 Java 17 中是预览功能,因此需要通过命令行参数 --enable-preview 来启用。switch 在很多时候可以替代嵌套的 if/else。
下面的代码使用 switch 语句加上模式匹配改写了上面的使用嵌套 if/else 的代码示例。使用 switch 比 if/else 更加简洁。这里的 switch 用的是箭头格式。
public class StringMatch {
public void test(Object obj) {
switch (obj) {
case String s && s.length() > 10 -> System.out.println(
"长字符串 -> " + s);
case String s -> System.out.println("短字符串 -> " + s);
default -> System.out.println("其他");
}
}
}
我们可以用 switch 语句改写文章开头提到的对象格式化的方法,如下面的代码所示。使用 switch 语句加上模式匹配的代码更加简洁易懂。
public class ObjectFormatter {
public String format(Object input) {
return switch (input) {
case null -> "";
case Number n -> NumberFormat.getNumberInstance().format(n);
case LocalDateTime t -> t.format(DateTimeFormatter.ISO_DATE_TIME);
default -> input.toString();
};
}
}