Krzysztof Majewski Krzysztof Majewski - 1 year ago 101
Java Question

java.lang.NullPointerException is thrown using a method-reference but not a lambda expression

I've noticed something weird about unhandled exceptions using Java 8 method reference. This is my code, using the lambda expression

() -> s.toLowerCase()

public class Test {

public static void main(String[] args) {

private static void testNPE(String s) {
Thread t = new Thread(() -> s.toLowerCase());
// Thread t = new Thread(s::toLowerCase);
t.setUncaughtExceptionHandler((t1, e) -> System.out.println("Exception!"));

It prints "Exception", so it works fine. But when I change
Thread t
to use a method-reference (even IntelliJ suggests that):

Thread t = new Thread(s::toLowerCase);

the exception is not being caught:

Exception in thread "main" java.lang.NullPointerException
at Test.testNPE(
at Test.main(
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(
at sun.reflect.DelegatingMethodAccessorImpl.invoke(
at java.lang.reflect.Method.invoke(
at com.intellij.rt.execution.application.AppMain.main(

Can someone explain what is going on here?

Answer Source

This behaviour relies on a subtle difference between the evaluation process of method-references and lambda expressions.

From the JLS Run-Time Evaluation of Method References:

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.

With the following code:

Thread t = new Thread(s::toLowerCase); // <-- s is null, NullPointerException thrown here
t.setUncaughtExceptionHandler((t1, e) -> System.out.println("Exception!"));

the expression s is evaluated to null and an exception is thrown exactly when that method-reference is evaluated. However, at that time, no exception handler was attached, since this code would be executed after.

This doesn't happen in the case of a lambda expression, because the lambda will be evaluated without its body being executed. From Run-Time Evaluation of Lambda Expressions:

Evaluation of a lambda expression is distinct from execution of the lambda body.

Thread t = new Thread(() -> s.toLowerCase());
t.setUncaughtExceptionHandler((t1, e) -> System.out.println("Exception!"));

Even if s is null, the lambda expression will be correctly created. Then the exception handler will be attached, the thread will start, throwing an exception, that will be caught by the handler.

As a side-note, it seems Eclipse Mars.2 has a small bug regarding this: even with the method-reference, it invokes the exception handler. Eclipse isn't throwing a NullPointerException at s::toLowerCase when it should, thus deferring the exception later on, when the exception handler was added.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download