人们已经意识到了很多问题,即使用表达式的结果为null
的表达式创建方法引用将导致NullPointerException
。例如:
String s = null;
Supplier<char[]> fun = s::toCharArray;
这归因于Java规范中的以下段落:
首先,如果方法引用表达式以ExpressionName或Primary开头,则将评估此子表达式。如果子表达式的计算结果为null,则引发NullPointerException,并且方法引用表达式突然完成。如果子表达式突然完成,则由于相同的原因,方法引用表达式也会突然完成。
现在我的问题是,有谁碰巧知道这个(基于许多困惑的问题)违反直觉规范的原因是什么?
我唯一想到的是,在以下情况下,如果在评估NullPointerException
期间发生Supplier
的错误,则很难准确报告该错误:
public static char[] callback(Supplier<char[]> supplier) {
return supplier.get();
}
public static void main(String[] args) {
String s = null;
callback(s::toCharArray);
}
答案 0 :(得分:7)
这里的原因是,当您创建非静态方法引用时,它必须有权访问this
。当您尝试创建对空对象的引用时,在任何地方都没有this
,这就是为什么它应该在此步骤中失败的原因,而不是第一次使用它时在代码中的某个地方失败。
想象一下,在一个地方得到对象,将它的方法引用保存在某个地方,然后在完全不同的代码部分中使用它。您将得到的NPE不在发生错误的地方,而是许多行代码。
答案 1 :(得分:2)
因为Java编译器不是linter /逻辑检查器。
Java中没有什么能阻止您通过取消引用null
来触发NPE。
例如,Java不会阻止您这样做:
String s = null;
s.toString();
那是在Java 8之前,而在今天仍然是方法参考。
您引用的段落仅详细说明了JVM如何在运行时处理方法引用这一点,即如果方法引用评估的一部分失败,则整个评估都会失败。
请注意,在您的实际示例中,IDE可能会发出警告,因为潜在错误的范围非常狭窄。