NullPointer通过Java三元运算符的自动装箱行为的异常

前几天,我绊倒了一个非常奇怪的,这是由三元运算符中意外的类型转换引起的。给定此(无用的示例性)函数:NullPointerException

Integer getNumber() {
    return null;
}

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

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

与。

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

.

事实证明,如果 是 ,-语句工作正常,而第二个代码段中的三元 opration 会抛出一个 .似乎三元运算已经决定在将结果自动装箱回!?!事实上,如果我显式地将 to 转换为 ,则异常会消失。换句话说:conditiontrueifNullPointerExceptionintInteger0Integer

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

不等同于:

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

.

因此,似乎三元运算符和等效的 -语句之间存在字节码差异(这是我没想到的)。这就提出了三个问题:为什么会有差异?这是三元实现中的错误,还是类型强制转换的原因?鉴于存在差异,三元运算的性能是否比等效的-语句更高或更低(我知道,差异不可能很大,但仍然如此)?if-elseif


答案 1

根据JLS: -

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

  • 如果第二个和第三个操作数具有相同的类型(可能是 null 类型),则这就是条件表达式的类型。
  • 如果第二个和第三个操作数之一是基元类型 T,而另一个操作数的类型是将装箱转换
    (§5.1.7) 应用于 T 的结果,则条件表达式的类型为 T。

答案 2

问题是:

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

强制对 getNumber() 的结果进行拆箱和重新装箱。这是因为三元 (0) 的 false 部分是整数,因此它尝试将 getNumber() 的结果转换为 int。而以下情况则不然:

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

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


推荐