通过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语句工作正常,而第二个代码段中的三元操作会抛出一个NullPointerExceptionexception。 看起来好像三元操作已经决定在将结果自动装箱回到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将不会影响结果。