Java方法引用中表达式的运行时评估

man*_*uti 8 java eclipse java-8 method-reference

在Java语言规范的方法引用运行时评估部分中,提到:

在运行时,方法引用表达式的求值类似于类实例创建表达式的求值,只要正常完成产生对对象的引用即可.方法引用表达式的评估不同于方法本身的调用.

首先,如果方法引用表达式以ExpressionNamePrimary开头,则计算此子表达式.如果子表达式求值为null,NullPointerException则引发a,并且方法引用表达式突然完成.如果子表达式突然完成,则方法引用表达式会出于同样的原因突然完成.

ExpressionName中被定义方法参考表达式语法:

MethodReference:
Run Code Online (Sandbox Code Playgroud)
  ExpressionName :: [TypeArguments] Identifier
  ReferenceType :: [TypeArguments] Identifier
  Primary :: [TypeArguments] Identifier
  super :: [TypeArguments] Identifier
  TypeName . super :: [TypeArguments] Identifier
  ClassType :: [TypeArguments] new
  ArrayType :: new 
Run Code Online (Sandbox Code Playgroud)

我对突出显示的部分感兴趣,并希望使用以下代码测试提到的行为:

public class Test {

    public static void main(String[] args) {
        System.out.println("Testing...");
        final Person p = null;
        foo(p::getName); // I was expecting an NPE here
    }

    private static void foo(Supplier<String> supplier) {
        System.out.println(supplier);

        // supplier.get();  // uncommenting this causes an NPE, but not when evaluating
                            // the method reference, but rather when the method is invoked.
    }

    static class Person {
        String getName() {
            return "x";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,该行foo(p::getName)不会抛出NullPointerException.我是否误解了JLS的上述引用?如果是,有人可以解释更多上述引用的含义或给出一个例子吗?

Eug*_*ene 7

哦,真是太棒了!那是一个eclipse bug(ECJ),它失败了javac/java(我在这个例子中尝试了9,但是同样的事情发生在8):

 Testing...
 Exception in thread "main" java.lang.NullPointerException
 at java.base/java.util.Objects.requireNonNull(Objects.java:221)
 at org.eugene.so.DeleteMe.main(DeleteMe.java:11)
Run Code Online (Sandbox Code Playgroud)

  • @Andreas:"b119"指的是"beta 119"(请注意该评论的日期).虽然我手头没有测试版119,但我可以断言,抛出NPE的指定行为会在以后的版本中显示,尤其是所有发行版本; 我在这里测试的最早版本是b132.目前尚不清楚,该评论者使用了哪种设置,但在问题已经结束时添加了评论. (5认同)