方法引用表达式评估中的空检查背后是什么原因?

时间:2018-12-12 13:27:22

标签: java java-8 nullpointerexception method-reference

人们已经意识到了很多问题,即使用表达式的结果为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);
}

2 个答案:

答案 0 :(得分:7)

这里的原因是,当您创建非静态方法引用时,它必须有权访问this。当您尝试创建对空对象的引用时,在任何地方都没有this,这就是为什么它应该在此步骤中失败的原因,而不是第一次使用它时在代码中的某个地方失败。

想象一下,在一个地方得到对象,将它的方法引用保存在某个地方,然后在完全不同的代码部分中使用它。您将得到的NPE不在发生错误的地方,而是许多行代码。

答案 1 :(得分:2)

因为Java编译器不是linter /逻辑检查器。
Java中没有什么能阻止您通过取消引用null来触发NPE。
例如,Java不会阻止您这样做:

String s = null;
s.toString();

那是在Java 8之前,而在今天仍然是方法参考。

您引用的段落仅详细说明了JVM如何在运行时处理方法引用这一点,即如果方法引用评估的一部分失败,则整个评估都会失败。

请注意,在您的实际示例中,IDE可能会发出警告,因为潜在错误的范围非常狭窄。