通过Java三元运算符的自动装箱行为发生NullPointerException
我绊倒了一个非常奇怪的NullPointerException
这是由三元运算符中意外的types转换造成的。 鉴于这个(无用的示例)function:
Integer getNumber() { return null; }
我期待编译后的以下两段代码段完全相同:
Integer number; if (condition) { number = getNumber(); } else { number = 0; }
与
Integer number = (condition) ? getNumber() : 0;
。
事实certificate,如果condition
为true
,那么if
语句工作正常,而第二个代码段中的三元操作会抛出一个NullPointerException
exception。 看起来好像三元操作已经决定在将结果自动装箱回到Integer
之前,将这两个选项都input到int
! 事实上,如果我明确地将0
为Integer
,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
语句。 if
和else
的主体是声明 ,而接下来的部分是?
和:
是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
将不会影响结果。