我一直在尝试 Java 21 中的模式匹配与记录模式的示例。官方文档断言空值不匹配任何记录模式。不过,我尝试这个例子:
record Point(Integer x, Integer y) {}
public class MainPatternMatchingRecord {
public static void main(String[] args) {
printSum(new Point(null, 2));
}
private static void printSum(Object obj) {
if (obj instanceof Point(var x, var y)) {
System.out.println(x + 1);
}
}
}
这里,根据我对 JEP 的理解, new Point(null, 2) 不应该匹配 instanceof Point(var x, var y) 但是当运行程序时,会抛出这个异常:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "x" is null
为什么会出现这种行为?应该如何正确解释空值与任何记录模式不匹配?
JEP 440确实说:
空值与任何记录模式都不匹配。
但是仔细看看记录模式是什么:
记录模式由记录类类型和(可能为空)模式列表组成[...]
JEP 还指定了如下记录模式的语法:
Pattern:
TypePattern
RecordPattern
TypePattern:
LocalVariableDeclaration
RecordPattern:
ReferenceType ( [ PatternList ] )
PatternList :
Pattern { , Pattern }
通过这些定义,我们可以看到
var x
和var y
是不是记录模式。它们是类型模式。 “空值与任何记录模式都不匹配”的规则在这里不适用。
我无法准确找到 JEP 中说记录模式中的类型模式的行为是这样的,但 预览规范 确实明确指出了这一点:
考虑一下,例如:
class Super {} class Sub extends Super {} record R(Super s) {}
我们期望
类型的所有非空值都与模式匹配R
,包括评估结果的值 表情R(Super s)
。 (即使空值不匹配 模式new R(null)
。)但是,我们不希望该值与模式Super s
匹配,因为记录组件的R(Sub s)
值与模式null
不匹配。Sub s
这是另一个例子:
record Foo(Integer x, Integer y) {}
record Bar(Foo a, Foo b) {}
private static void printSum(Object obj) {
if (obj instanceof Bar(Foo(Integer x1, Integer y1), Foo(var x2, var y2))) {
System.out.println("matched!");
}
}
现在,
new Bar(null, null)
将不匹配模式Bar(Foo(Integer x1, Integer y1), Foo(var x2, var y2))
,因为Foo(Integer x1, Integer y1)
是一个记录模式,而null
与它不匹配。