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

Mar*_* A. 15 java autoboxing nullpointerexception ternary

NullPointerException几天我在三元运算符中意外地进行了类型转换,这让我感到非常奇怪.鉴于此(无用的示例)功能:

Integer getNumber() {
    return null;
}
Run Code Online (Sandbox Code Playgroud)

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

Integer number;
if (condition) {
    number = getNumber();
} else {
    number = 0;
}
Run Code Online (Sandbox Code Playgroud)

Integer number = (condition) ? getNumber() : 0;
Run Code Online (Sandbox Code Playgroud)

.

事实证明,如果conditiontrue,if-statement工作正常,而第二个代码段中的三元操作抛出一个NullPointerException.似乎三元操作决定int在将结果自动装箱之前将两种选择都输入到一个Integer!?!事实上,如果我明确地转换0Integer,则异常消失.换一种说法:

Integer number = (condition) ? getNumber() : 0;
Run Code Online (Sandbox Code Playgroud)

是不一样的:

Integer number = (condition) ? getNumber() : (Integer) 0;
Run Code Online (Sandbox Code Playgroud)

.

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

Roh*_*ain 15

根据JLS: -

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

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


Cra*_*sta 11

问题是:

Integer number = (condition) ? getNumber() : 0;
Run Code Online (Sandbox Code Playgroud)

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

Integer number = (condition) ? getNumber() : (Integer) 0;
Run Code Online (Sandbox Code Playgroud)

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

  • @Markus参见[Java语言规范15.25](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25)`如果第二个和第三个操作数之一是原始类型T,另一个的类型是对T应用装箱转换(第5.1.7节)的结果,那么条件表达式的类型是T. (2认同)