NullPointerException通过Java三元运算符的自动装箱行为

时间:2012-10-06 21:21:45

标签: java nullpointerexception autoboxing ternary

前几天,我在三元运算符中意外地进行了类型转换,导致了一个非常奇怪的NullPointerException。鉴于此(无用的示例性)功能:

Integer getNumber() {
    return null;
}

我希望编译后以下两个代码段完全相同:

Integer number;
if (condition) {
    number = getNumber();
} else {
    number = 0;
}

VS

Integer number = (condition) ? getNumber() : 0;

原来,如果conditiontrueif - 语句可以正常工作,而第二个代码段中的三元操作会抛出NullPointerException。似乎三元操作决定在将结果自动装回int之前将两个选项输入到Integer!!事实上,如果我明确地将0强制转换为Integer,那么例外就会消失。换句话说:

Integer number = (condition) ? getNumber() : 0;

与:

不同
Integer number = (condition) ? getNumber() : (Integer) 0;

因此,似乎三元运算符和等效的if-else语句之间存在字节码差异(我没想到的是这种情况)。这提出了三个问题:为什么会有差异?这是三元实现中的错误还是有类型转换的原因?鉴于存在差异,三元运算的性能是否比同等的if语句更高或更低(我知道,差异不是很大,但仍然存在)?

3 个答案:

答案 0 :(得分:14)

根据JLS: -

  

条件表达式的类型确定如下:

     
      
  • 如果第二个和第三个操作数具有相同的类型(可能是null类型),那么这是条件的类型   表达
  •   
  • 如果第二个和第三个操作数之一是原始类型T,而另一个的类型是应用装箱转换的结果
      (§5.1.7)到T,那么条件表达式的类型是T。
  •   

答案 1 :(得分:11)

问题在于:

Integer number = (condition) ? getNumber() : 0;

强制取消装箱并重新装箱getNumber()的结果。这是因为三元组(0)的错误部分是一个整数,所以它试图将getNumber()的结果转换为int。以下不是:

Integer number = (condition) ? getNumber() : (Integer) 0;

这不是一个错误,只是Java选择做事的方式。

答案 2 :(得分:2)

这是应该如何工作的。三元运算符 not 意味着等同于常规if语句。 ifelse的正文是语句,而?:之后的部分是表达式,需要评估相同的类型。

换句话说:a = b ? c : d不应该等同于if (b) a = c; else a = d;。相反,b ? c : d本身就是一个表达式,将结果赋给a不会影响结果。