2

Why does this throw a NullPointerException? The docs for Java 8 state that: "If a value is present, invoke the specified consumer with the value, otherwise do nothing."

    public static void main(String[] args) {

        List<String> uninitialisedList = getList();
        Optional<String> opt = Optional.empty();
        opt.ifPresent(uninitialisedList::add);
    }

    private static List<String> getList() {
        return null;
    }
1
  • Because uninitialisedList::add must still be evaluated and uninitializedList is null. Commented Mar 11 at 14:30

2 Answers 2

8

This is because the method reference expression uninitialisedList::add throws a NullPointerException when uninitialisedList is null. From the Java Language Specification:

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.

Even though the add method is not actually called (as the documentation for ifPresent says, it will not be called in this case), the method reference expression still needs to be evaluated before calling ifPresent, because it is an argument of ifPresent. And evaluating the method reference expression is when the NullPointerException is thrown.

Intuitively, uninitialisedList::add is a "reference" to the add method on uninitialisedList. If uninitialisedList is null, there is no such method, so it is natural for an exception to be thrown.

Compare this with a lambda expression:

opt.ifPresent(x -> uninitialisedList.add(x));

Evaluating the lambda expression does not throw a NullPointerException (see the relevant section in the JLS). It just creates a new object implementing the functional interface. As long as the lambda body is not executed, it's all fine.

5

The NPE is not thrown by the Optional, it is thrown by the method reference - uninitialisedList::add. You can't use method reference on a null object - there is an internal check for this.

Even if the optional contains value, you will still get NPE, because of the null check:

opt = Optional.of("qwerty");
opt.ifPresent(uninitialisedList::add);
//above line throws NullPointerException as well
//because uninitialisedList is null

This behaviour is defined in JLS 15.13.3. Run-Time Evaluation of Method References:

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.

You can use safely use 'normal' lambda function on the other hand:

opt.ifPresent(val -> uninitialisedList.add(val));

Not the answer you're looking for? Browse other questions tagged or ask your own question.