I'm trying to write method that converts a two digit number to 2000 + the number, returns all other numbers as they are and returns null when a null is passed as an argument.
This implementation works as intended
private Integer convertTo4Digits(Integer modelYear) {
boolean isTwoDigit = modelYear != null && modelYear < 100;
if (isTwoDigit) {
return 2000 + modelYear;
} else {
return modelYear;
}
}
But this one fails with a NPE in the return statement when called with NULL.
private Integer convertTo4Digits(Integer modelYear) {
return (modelYear != null && modelYear < 100) ? (2000 + modelYear) : modelYear;
}
Or is this a Bug? I'm using Eclipse Keple with JDK 1.7.0_04
I think the answer can be found in chapter 15.25 of the JLS
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.
So when either the second or third operand is a primitive type the expression's type is a primitive. Thus if you pass a null
reference the branch : modelYear
will be executed. But since one operand is primitive it must be unboxed. This causes the NPE.
You can also see this if you take a look at the generated byte code
private convertTo4Digits(Ljava/lang/Integer;)Ljava/lang/Integer;
L0
LINENUMBER 46 L0
ALOAD 1
IFNULL L1
ALOAD 1
INVOKEVIRTUAL java/lang/Integer.intValue()I
BIPUSH 100
IF_ICMPGE L1
SIPUSH 2000
ALOAD 1
INVOKEVIRTUAL java/lang/Integer.intValue()I
IADD
GOTO L2
L1
LINENUMBER 47 L1
ALOAD 1
INVOKEVIRTUAL java/lang/Integer.intValue()I
L2
LINENUMBER 46 L2
INVOKESTATIC java/lang/Integer.valueOf(I)Ljava/lang/Integer;
ARETURN
Your own answer solves the problem because you are casting the second operand to Integer
(modelYear != null && modelYear < 100) ? (Integer) (2000 + modelYear) : modelYear;
and therefore neither the second nor the thrid operand are of primitive type. Thus the rule of the JLS I posted above is not applied and the NPE is gone.
Oh darn, this one works (note the explicit cast to Integer):
(modelYear != null && modelYear < 100) ? (Integer) (2000 + modelYear) : modelYear;
The problem is: the first branch of the ternary operator determines the result type of the operator: int in the version of the question
Now the modelYear (null) gets unboxed which causes the NPE right before it gets boxed again.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.