简体   繁体   English

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

[英]NullPointerException through auto-boxing-behavior of Java ternary operator

I tripped across a really strange NullPointerException the other day caused by an unexpected type-cast in the ternary operator.前几天我遇到了一个非常奇怪的NullPointerException这是由三元运算符中的意外类型转换引起的。 Given this (useless exemplary) function:鉴于这个(无用的示例)功能:

Integer getNumber() {
    return null;
}

I was expecting the following two code segments to be exactly identical after compilation:我期望编译后以下两个代码段完全相同:

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

vs.对比

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

. .

Turns out, if condition is true , the if -statement works fine, while the ternary opration in the second code segment throws a NullPointerException .事实证明,如果conditiontrue ,则if语句工作正常,而第二个代码段中的三元操作会抛出NullPointerException It seems as though the ternary operation has decided to type-cast both choices to int before auto-boxing the result back into an Integer !?!似乎三元运算决定在将结果自动装箱回Integer之前将两个选项都类型转换为int !?! In fact, if I explicitly cast the 0 to Integer , the exception goes away.事实上,如果我显式地将0Integer ,异常就会消失。 In other words:换句话说:

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

is not the same as:不等同于:

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

. .

So, it seems that there is a byte-code difference between the ternary operator and an equivalent if-else -statement (something I didn't expect).因此,三元运算符和等效的if-else语句之间似乎存在字节码差异(这是我没想到的)。 Which raises three questions: Why is there a difference?这就提出了三个问题:为什么会有差异? Is this a bug in the ternary implementation or is there a reason for the type cast?这是三元实现中的错误还是类型转换的原因? Given there is a difference, is the ternary operation more or less performant than an equivalent if -statement (I know, the difference can't be huge, but still)?鉴于存在差异,三元运算的性能是否比等效的if语句更高或更低(我知道,差异不会很大,但仍然如此)?

According to JLS : -根据JLS :-

The type of a conditional expression is determined as follows:条件表达式的类型确定如下:

  • If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.如果第二个和第三个操作数具有相同的类型(可能是空类型),那么这就是条件表达式的类型。
  • If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion如果第二个和第三个操作数之一是原始类型 T,另一个的类型是应用装箱转换的结果
    (§5.1.7) to T, then the type of the conditional expression is T. (§5.1.7) 到 T,则条件表达式的类型为 T。

The problem is that:问题在于:

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

Forces an unboxing and reboxing of the result of getNumber().强制对 getNumber() 的结果进行拆箱和重新装箱。 This is because the false part of the ternary (0) is an integer, so it tries to convert the result of getNumber() to an int.这是因为三元 (0) 的 false 部分是整数,因此它尝试将 getNumber() 的结果转换为 int。 Whereas the following does not:而以下不是:

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

This is not a bug, just the way Java chose to do things.这不是错误,只是 Java 选择做事的方式。

This is how it is supposed to work.这就是它应该如何工作。 The ternary operator is not meant to be equivalent to a regular if statement.三元运算符并不意味着等同于常规if语句。 The bodies of if and else are statements , while the parts following ? ifelse的主体是语句,而后面的部分是? and : are expressions , that are required to evaluate to the same type.:表达式,需要计算为相同的类型。

Put another way: a = b ? c : d换句话说: a = b ? c : d a = b ? c : d is not supposed to be equivalent to if (b) a = c; else a = d; a = b ? c : d不应该等价于if (b) a = c; else a = d; if (b) a = c; else a = d; . . Instead, b ? c : d相反, b ? c : d b ? c : d is an expression on its own, and the assignment of its result to a won't affect the outcome. b ? c : d本身就是一个表达式,将其结果赋值给a不会影响结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM