8

In section Run-Time Evaluation of Method References of the Java Language Specification, it is mentioned that:

At run time, evaluation of a method reference expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a method reference expression is distinct from invocation of the method itself.

First, if the method reference expression begins with an ExpressionName or a Primary, this subexpression is evaluated. If the subexpression evaluates to null, a NullPointerException is raised, and the method reference expression completes abruptly. If the subexpression completes abruptly, the method reference expression completes abruptly for the same reason.

And ExpressionName and Primary are defined in the method reference expression syntax:

MethodReference:
  ExpressionName :: [TypeArguments] Identifier
  ReferenceType :: [TypeArguments] Identifier
  Primary :: [TypeArguments] Identifier
  super :: [TypeArguments] Identifier
  TypeName . super :: [TypeArguments] Identifier
  ClassType :: [TypeArguments] new
  ArrayType :: new 

I was interested by the highlighted part and wanted to test the mentioned behavior using the below code:

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";
        }
    }
}

However, the line foo(p::getName) does not throw a NullPointerException. Am I misunderstanding the above quote from the JLS? If yes, could someone explain more the meaning of the above quote or give an example where it would occur?

M A
  • 71,713
  • 13
  • 134
  • 174
  • 1
    interesting, I would have expecting it to throw the exception indeed and I tried changing it to a lambda expression (thinking this for sure will break), but it did not. good question – Eugene Dec 14 '17 at 15:30
  • I agree, according to the spec, the `p::getName` method reference should have thrown the NPE. Guess they didn't add that validation, so the NPE is deferred until actually used. See related [JDK-8131323](https://bugs.openjdk.java.net/browse/JDK-8131323). – Andreas Dec 14 '17 at 15:38
  • 1
    There is an [earlier question about it](https://stackoverflow.com/q/37681625/2711488), however, no link to a report in the Eclipse bug tracker there. I’m quiet sure, I have seen one in the past… – Holger Dec 14 '17 at 15:59
  • @Holger excellent find - then this is a duplicate I guess – Eugene Dec 14 '17 at 15:59
  • 5
    https://bugs.eclipse.org/bugs/show_bug.cgi?id=521182 – Holger Dec 14 '17 at 16:04
  • @Holger I was just about to create a new bug :) Thanks for the helpful link. – M A Dec 14 '17 at 16:07

1 Answers1

7

Oh darn! That's an eclipse bug (ECJ), it fails with javac/java (I've tried 9 here in the example, but same thing happens in 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)
Holger
  • 285,553
  • 42
  • 434
  • 765
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • 1
    According to [JDK-8131323](https://bugs.openjdk.java.net/browse/JDK-8131323), you no longer get NPE with jdk 8 b119, even though bug is closed as "Not an Issue", given the spec calls for NPE. – Andreas Dec 14 '17 at 15:39
  • 5
    @Andreas: “b119” refers to “beta 119” (note the date of that comment). While I don’t have beta 119 at hand, I can assert you that the specified behavior of throwing an NPE is shown by later versions, especially all release versions; the earliest version I have here for testing is b132. It’s not clear, which setup the commenter used, but the comment has been added when the issue was already closed. – Holger Dec 14 '17 at 15:50
  • 1
    @Holger DOH! Was think `u119` when I saw that `b119`. – Andreas Dec 14 '17 at 17:36