什么情况下,当方法返回布尔值且使用三元运算符作为返回时,仍然可以编译通过?

3

为什么这段代码可以编译?我原本以为编译器会抱怨“类型不匹配:无法将null转换为布尔值”,但它没有。实际运行时,它只是因为NullPointerException而失败。

public static void main(String[] args) throws Exception {
    System.out.println("this throws a NPE: " + whyIsThisPossible(1, 2));
}

private static boolean whyIsThisPossible(int a, int b) {
    return a + b == 2 ? true : null;
}

Exception in thread "main" java.lang.NullPointerException
at FunkyMethodTest.whyIsThisPossible(FunkyMethodTest.java:10)
at FunkyMethodTest.main(FunkyMethodTest.java:5)*
3个回答

3
Java 将三元表达式的类型视为布尔类型。编译器将 null 视为 Boolean,也就是将 boolean 的原始类型应用装箱转换后的结果。以下是相关部分的语言规范:
15.25 条件表达式的类型确定如下: ... 如果第二个和第三个操作数中的一个是基本类型 T,并且另一个操作数的类型是将 T 应用装箱转换(§5.1.7)的结果,则条件表达式的类型为 T。
语言规范指出,当必要时,将应用装箱/拆箱转换到表达式条件所选择的操作数。这就是在代码试图从 null 中取消装箱的 boolean 时触发异常的原因。

0

三元运算符的第一部分决定了操作数的类型,在这种情况下为原始类型 boolean

return a + b == 2 ? true : null;

请注意,您可以(语法上)将null(技术上为NullType)转换为boolean,但这会导致NullPointerException。 因此,尽管代码编译成功,如果a + b不等于2,则会出现NullPointerException。至于为什么它在语法上是合法的,请考虑:
return a + b == 2 ? true : Boolean.FALSE;

请注意,Boolean.FALSE 是一个 Boolean 类型,自动拆箱意味着这段代码可以正常工作。

0

这个 return a + b == 2 ? true : (Boolean) x; 是实际发生的事情,尽管你不能直接写出来,因为编译器会报错。但你可以这样写:

private static boolean whyIsThisPossible(int a, int b) {
    Boolean x = null;
    if (a == b) {
        x = false;
    }
    return a + b == 2 ? true : (Boolean) x;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接