前几天,我在三元运算符中意外地进行了类型转换,导致了一个非常奇怪的NullPointerException
。鉴于此(无用的示例性)功能:
Integer getNumber() {
return null;
}
我希望编译后以下两个代码段完全相同:
Integer number;
if (condition) {
number = getNumber();
} else {
number = 0;
}
VS
Integer number = (condition) ? getNumber() : 0;
原来,如果condition
是true
,if
- 语句可以正常工作,而第二个代码段中的三元操作会抛出NullPointerException
。似乎三元操作决定在将结果自动装回int
之前将两个选项输入到Integer
!!事实上,如果我明确地将0
强制转换为Integer
,那么例外就会消失。换句话说:
Integer number = (condition) ? getNumber() : 0;
与:
不同Integer number = (condition) ? getNumber() : (Integer) 0;
因此,似乎三元运算符和等效的if-else
语句之间存在字节码差异(我没想到的是这种情况)。这提出了三个问题:为什么会有差异?这是三元实现中的错误还是有类型转换的原因?鉴于存在差异,三元运算的性能是否比同等的if
语句更高或更低(我知道,差异不是很大,但仍然存在)?
答案 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
语句。 if
和else
的正文是语句,而?
和:
之后的部分是表达式,需要评估相同的类型。
换句话说:a = b ? c : d
不应该等同于if (b) a = c; else a = d;
。相反,b ? c : d
本身就是一个表达式,将结果赋给a
不会影响结果。