Java: Does lambda and method reference have different execution timing?

Viewed 87

Code:

@FunctionalInterface
interface VoidSupplier {
    void apply() throws Exception;
}

void execute(VoidSupplier voidSupplier) {
    if (voidSupplier != null) {
        try {
            voidSupplier.apply();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

Call execute use lambda:

@Test
public void testLambda() {
    InputStream i = null;
    execute(() -> i.close());       // use lambda
    System.out.println("output some message");  // will be executed
}

Call execute use method reference:

@Test
void testMethodReference() {
    InputStream i = null;
    execute(i::close);             //  use method reference
    System.out.println("output some message");   // will not be executed
}

When use lambda, execute(VoidSupplier) will be executed first, and then execute () -> i.close().
but use method reference, i::close will be executed first, and then execute execute(VoidSupplier).
Why lambda and method reference have different execution timing?

1 Answers

execute(VoidSupplier voidSupplier) is a method. Prior to executing this method, its argument must be evaluated, regardless of whether it's a lambda expression or a method reference.

The lambda expression snippet:

In order for the lambda expression to be evaluated, there's no need to execute the lambda expression body. Therefore, the expression () -> i.close() doesn't throw an exception. Only when execute is executed, NullPointerException is thrown when voidSupplier.apply() is executed, and you catch that exception, allowing the System.out.println to be executed.

The method reference snippet:

If you use a null reference as the left side of a method reference, the evaluation of the method reference will result in NullPointerException:

J.L.S. 15.3.3. 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. If the subexpression completes abruptly, the method reference expression completes abruptly for the same reason.

This means evaluating i::close throws NullPointerException, and execute() is not executed. Since you don't catch this exception, your System.out.println statement is never reached.

Related