我有 Java 19,我正在尝试对我创建的记录进行一些简单的模式匹配。然而,Java 给了我一个非常令人困惑的编译错误。这是我可以做的导致错误的最简单的例子。
public class ExpressionTypeIsASubsetOfPatternType
{
public record Triple(int a, int b, int c) {}
public static void main(String[] args)
{
System.out.println("Java Version = " + System.getProperty("java.version"));
final Triple input = new Triple(1, 2, 3);
if (input instanceof Triple t)
{
System.out.println("Made it here");
}
}
}
这是当我尝试运行/编译时它给我的错误。
$ java ExpressionTypeIsASubsetOfPatternType.java
ExpressionTypeIsASubsetOfPatternType.java:15: error: expression type Triple is a subtype of pattern type Triple
if (input instanceof Triple t)
^
1 error
error: compilation failed
令人惊讶的是,谷歌搜索此错误没有显示任何有用的信息。我已经习惯了输入错误并立即发现问题。我想这是因为这个功能太新了。
无论如何,我能找到的最接近的东西是一个相关的bug,但绝对不是我正在处理的同一问题。
最后,这是我的java版本的相关信息。
$ java --version
openjdk 19 2022-09-20
OpenJDK Runtime Environment (build 19+36-2238)
OpenJDK 64-Bit Server VM (build 19+36-2238, mixed mode, sharing)
$ javac --version
javac 19
HTNW 的答案 是正确的响应,但我发现编译器的这种行为并不理想,因为它没有考虑空引用。这里有一些不一致之处:
String s = null;
if (s instanceof String) {}
String s = null;
if (s instanceof String string) {}
第一个选项将编译,第二个选项将给出错误“模式类型‘字符串’与表达式类型相同”。这意味着
instanceof
可以用作空检查,但如果使用模式匹配则不能。没有意义。
Java 只是“很好”:它认识到测试将always成功(因为
input
已知是Triple
,它已经是测试类型Triple
的子类型),因此它产生一个错误告诉您您正在做一些无用的事情(带有迂回消息)。
这也是同样的想法
void foo() {
return;
return; // error: unreachable statement
}
错误:有一段无用的代码可能表明(严重的)程序员错误,因此编译器迫使您重新考虑代码。
JLS 的相关部分是15.20.2,其中写着
表达式实例:
- ...
- 关系表达式
模式instanceof
...
当
是模式匹配运算符时,适用以下规则:instanceof
- ...
- 如果 RelationalExpression 的类型是 Pattern 类型的子类型,则会发生编译时错误。
即这确实是该语言的预期部分,而不仅仅是编译器错误或其他东西。
我完全同意@kingds的观点,即我们在执行空检查时不能使用模式匹配是没有意义的。
我遇到了同样的错误,我的愚蠢修复是将操作数向下转换为
Object
:
if ((Object)input instanceof Triple t) {
// ...
}
现在 Java 很高兴,因为它正在测试某些泛型
Object
是否可能是 Triple
实例。