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