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

我绊倒了一个非常奇怪的NullPointerException这是由三元运算符中意外的types转换造成的。 鉴于这个(无用的示例)function:

 Integer getNumber() { return null; } 

我期待编译后的以下两段代码段完全相同:

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

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

事实certificate,如果conditiontrue ,那么if语句工作正常,而第二个代码段中的三元操作会抛出一个NullPointerExceptionexception。 看起来好像三元操作已经决定在将结果自动装箱回到Integer之前,将这两个选项都input到int ! 事实上,如果我明确地将0Integer ,exception就会消失。 换一种说法:

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

不一样:

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

所以,似乎三元运算符和等价的if-else -statement(我没有想到的)之间有一个字节码的区别。 这就提出了三个问题:为什么有差异? 这是三元实现中的错误还是有types转换的原因? 鉴于有一个区别,是三元操作或多或less性能比等效if语句(我知道,差异不能很大,但仍然)?

根据JLS :

条件expression式的types如下确定:

  • 如果第二个和第三个操作数具有相同的types(可能是空types),那么这就是条件expression式的types。
  • 如果第二个和第三个操作数中的一个是基本typesT,而另一个的types是应用装箱转换的结果
    (§5.1.7)给T,那么条件expression式的types是T.

问题是:

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

强制对getNumber()的结果进行拆箱和重新包装。 这是因为三元(0)的虚假部分是一个整数,所以它试图将getNumber()的结果转换为一个int。 而以下不是:

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

这不是一个错误,只是Javaselect做事情的方式。

这是应该如何工作的。 三元运算符等同于常规的if语句。 ifelse的主体是声明 ,而接下来的部分是?:expression式 ,需要评估到相同的types。

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