java - NullPointerException 而不是 null(JVM 错误?)

标签 java lambda jvm ternary-operator

我在当前版本的 Java 8 中发现了一个奇怪的行为。在我看来,下面的代码应该没问题,但是 JVM 抛出了一个 NullPointerException:

Supplier<Object> s = () -> false ? false : false ? false : null;
s.get(); // expected: null, actual: NullPointerException

不管是什么类型的 lambda 表达式(与 java.util.function.Function 相同)或使用什么泛型类型都没有关系。还可以有更有意义的表达式来代替 false 吗? :。上面的例子很短。这是一个更丰富多彩的示例:

Function<String, Boolean> f = s -> s.equals("0") ? false : s.equals("1") ? true : null;
f.apply("0"); // false
f.apply("1"); // true
f.apply("2"); // expected: null, actual: NullPointerException

但是这些代码片段运行良好:

Supplier<Object> s = () -> null;
s.get(); // null

Supplier<Object> s = () -> false ? false : null;
s.get(); // null

或者用函数:

Function<String, Boolean> f = s -> {
    if (s.equals("0")) return false;
    else if (s.equals("1")) return true;
    else return null;
};
f.apply("0"); // false
f.apply("1"); // true
f.apply("2"); // null

我测试了两个 Java 版本:

~# java -version

openjdk version "1.8.0_66-internal" OpenJDK Runtime Environment (build 1.8.0_66-internal-b01) OpenJDK 64-Bit Server VM (build 25.66-b01, mixed mode)

C:\>java -version

java version "1.8.0_51" Java(TM) SE Runtime Environment (build 1.8.0_51-b16) Java HotSpot(TM) 64-Bit Server VM (build 25.51-b03, mixed mode)

最佳答案

这与 lambda 表达式无关;很简单,在这种情况下,三元运算符的返回类型是 boolean,因此将使用自动拆箱。

这里也抛出了NPE:

public class Main {

    private static Object method() {
        return false ? false : false ? false : null;
    }

    public static void main(String[] args) {
        System.out.println(method());
    }
}

那么,这里到底发生了什么?

首先,根据 JLS §15.25 评估“嵌入”表达式 (false ? false : null) :

The conditional operator is syntactically right-associative (it groups right-to-left). Thus, a?b:c?d:e?f:g means the same as a?b:(c?d:(e?f:g)).

嵌入表达式的类型是Boolean(盒装boolean),所以falsenull可以放进去。

那么整个表达式就是:

false ? false : (Boolean expression)

然后,再次根据JLS §15.25 :

If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.

因此,第一个参数是原始类型boolean(规范中的T),另一个参数的类型是装箱的T (Boolean),所以整个表达式的类型都是boolean

然后,在运行时,嵌入表达式的计算结果为 null,它会自动拆箱为 boolean,从而导致 NPE。

关于java - NullPointerException 而不是 null(JVM 错误?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31970213/

相关文章:

java - 在 Struts 2 中为所有 URL 添加一个变量

java - 使用模拟器和 HttpURLConnection 出现未知主机异常

Java Lambda 到比较器的转换——中间表示

Java 类文件规范 - double 和长整型表示

java - 有没有办法阻止 Eclipse 在启动 Web 应用程序时打开浏览器?

java - 将 java 输出打印到文件

python - lambda *args, **kwargs : None

java - 为什么此代码会对 * 和 + 运算符引发 invalidAssignmentOperator 错误?

java - 单核jvm并发: are invisible updates possible?

memory-management - 分配后TLAB分配的对象是否共享?