使用方法引用而不是lambda表达式抛出java.lang.NullPointerException [英] java.lang.NullPointerException is thrown using a method-reference but not a lambda expression

查看:1081
本文介绍了使用方法引用而不是lambda表达式抛出java.lang.NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到使用Java 8方法引用的未处理异常有些奇怪。这是我的代码,使用lambda表达式() - > s.toLowerCase()

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) {
        testNPE(null);
    }

    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!"));
        t.start();
    }
}

它打印Exception,所以它工作正常。但是,当我更改 Thread t 以使用方法引用时(甚至IntelliJ建议):

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);

未捕获异常:

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

有人能解释一下这里发生了什么吗?

Can someone explain what is going on here?

推荐答案

此行为依赖于方法引用和lambda表达式的评估过程之间的细微差别。

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

来自JLS 方法参考的运行时评估


首先,如果方法引用表达式以ExpressionName或Primary开头,则计算此子表达式。 如果子表达式求值为 null ,则会引发 NullPointerException ,并且方法引用表达式突然完成

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.

使用以下代码:

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

表达式 s 评估为 null 并且在评估该方法引用时会完全抛出异常。但是,那时没有附加异常处理程序,因为此代码将在执行之后执行。

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.

在lambda表达式的情况下不会发生这种情况,因为lambda将在不执行其正文的情况下进行评估。来自 Lambda的运行时评估表达式

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:


评估lambda表达式与执行lambda体不同。

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!"));

即使 s null ,将正确创建lambda表达式。然后将附加异常处理程序,线程将启动,抛出异常,将由处理程序捕获。

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.

作为旁注,Eclipse Mars.2似乎有一个小错误:即使使用方法引用,它也会调用异常处理程序。 Eclipse不应该在 s :: toLowerCase 中抛出 NullPointerException ,因此应该在以后延迟异常,添加了异常处理程序。

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.

这篇关于使用方法引用而不是lambda表达式抛出java.lang.NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆