NullPointerException through auto-boxing-behavior of Java ternary operator

半世苍凉 提交于 2019-12-17 03:42:26

问题


I tripped across a really strange NullPointerException the other day caused by an unexpected type-cast in the ternary operator. 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. 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!?! In fact, if I explicitly cast the 0 to Integer, the exception goes away. 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). 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)?


回答1:


According to 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
    (§5.1.7) to T, then the type of the conditional expression is T.



回答2:


The problem is that:

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

Forces an unboxing and reboxing of the result of 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. Whereas the following does not:

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

This is not a bug, just the way Java chose to do things.




回答3:


This is how it is supposed to work. The ternary operator is not meant to be equivalent to a regular if statement. The bodies of if and else are statements, while the parts following ? and : are expressions, that are required to evaluate to the same type.

Put another way: a = b ? c : d is not supposed to be equivalent to if (b) a = c; else a = d;. Instead, b ? c : d is an expression on its own, and the assignment of its result to a won't affect the outcome.



来源:https://stackoverflow.com/questions/12763983/nullpointerexception-through-auto-boxing-behavior-of-java-ternary-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!