Nullpointerexception Through Auto-Boxing-Behavior of Java Ternary Operator

NullPointerException through auto-boxing-behavior of Java ternary operator

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.

Why does ternary operator throw NPE in case of auto-unboxing?

Integer age = (testage != null) ? getDummyAge() : testage;

is equivalent to

Integer age = Integer.valueOf((testage != null) ? getDummyAge().intValue() : testage);

because numeric second and third operands of differing types undergo binary numeric promotion; the result of the conditional operator is int, which then has to be boxed back to Integer for the assignment.

This is as specified.

If you want to avoid the NPE, box the int explicitly:

Integer age = (testage != null) ? Integer.valueOf(getDummyAge()) : testage;

Boxed numerical operands of the same type are not unboxed.

Booleans, conditional operators and autoboxing

The difference is that the explicit type of the returnsNull() method affects the static typing of the expressions at compile time:

E1: `true ? returnsNull() : false` - boolean (auto-unboxing 2nd operand to boolean)

E2: `true ? null : false` - Boolean (autoboxing of 3rd operand to Boolean)

See Java Language Specification, section 15.25 Conditional Operator ? :

  • For E1, the types of the 2nd and 3rd operands are Boolean and boolean respectively, so this clause applies:

    If one of the second and third operands is of type boolean and the type of the other is of type Boolean, then the type of the conditional expression is boolean.

    Since the type of the expression is boolean, the 2nd operand must be coerced to boolean. The compiler inserts auto-unboxing code to the 2nd operand (return value of returnsNull()) to make it type boolean. This of course causes the NPE from the null returned at run-time.

  • For E2, types of the 2nd and 3rd operands are <special null type> (not Boolean as in E1!) and boolean respectively, so no specific typing clause applies (go read 'em!), so the final "otherwise" clause applies:

    Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).

    • S1 == <special null type> (see §4.1)
    • S2 == boolean
    • T1 == box(S1) == <special null type> (see last item in list of boxing conversions in §5.1.7)
    • T2 == box(S2) == `Boolean
    • lub(T1, T2) == Boolean

    So the type of the conditional expression is Boolean and the 3rd operand must be coerced to Boolean. The compiler inserts auto-boxing code for the 3rd operand (false). The 2nd operand doesn't need the auto-unboxing as in E1, so no auto-unboxing NPE when null is returned.


This question needs a similar type analysis:

Java conditional operator ?: result type

Java NPE in ternary operator with autoboxing?

The type of the expression item == null ? 1 : item.getId() is int not Integer. Therefore, Java needs to auto-unbox your Integer to an int (causing the NullPointerException). Then it auto-boxes the result back to an Integer (well it would if not for the NullPointerException) to return from the method.

On the other hand, the expression item == null ? new Integer(1) : item.getId() has a type of Integer and no auto-unboxing needs to be done.

When you auto-unbox a null Integer, you get a NullPointerException (see Autoboxing) and that is what you are experiencing.

To answer your question, this is correct behavior.

NullPointerException throws when I use ternary operator

You guessed it right. For a formal explanation, the answer lies in 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 as you have the primitive true and false in both expressions, the type of your condition expression is boolean.

When you get into the second expression, in the second case, the null reference is converted into boolean with null.booleanValue();, causing the NPE, so that the expression is equivalent to:

return Boolean.valueOf(null.booleanValue());

(then the return type of the expression is re-boxed to Boolean, but it's too late as you guessed it).

For example:

return ("true".equals(booleanString) ? Boolean.TRUE : ("false".equals(booleanString) ? Boolean.FALSE : null));

does not cause a NPE since the type of the expression is Boolean. This, however,

return ("true".equals(booleanString) ? true : ("false".equals(booleanString) ? Boolean.FALSE : null));

causes it because again the same rule applies (since the first expression is the primitive boolean type). So it's equivalent to:

return Boolean.valueOf(("true".equals(booleanString) ? true : ("false".equals(booleanString) ? Boolean.FALSE : null).booleanValue());

Auto-unboxing need of ternary if-else

The type of the ternary conditional expression

1 <= 3 ? nullInt : -1

is int (the JLS contains several tables that describe the type of the ternary conditional operator depending on the types of the 2nd and 3rd operands).

Therefore, when it tries to unbox nullInt to an int, a NullPointerException is thrown.

In order to get the behavior of your if-else snippet, you need to write:

1 <= 3 ? nullInt : Integer.valueOf(-1)

Now the type of the expression will be Integer, so no unboxing will take place.

java ternary conditions strange null pointer exception

When you use ternary operator,

 flag  ? type1 : type2

Type1 and type2 must be of same type while conversion. First it realises type1 and then type2.

Now look at your cases

 final Integer b = false ? 0 : a;

Since type1 is 0 and it takes as a primitive and since a is trying to convert it as a primitive. Hence the null pointer.

where as same tricky test5

 final Integer b = false ? a : 0;

Since a is of type Integer 0 boxed to wrapper integer and assigned to the LHS.

Unwanted NullPointerException in ternary operator - Why?

When you write

value = condition ? null : 1.0;

the type of condition ? null : 1.0 must be a reference type, so the type is Double, which can hold the value null.

When you write

value = condition ? getDouble() : 1.0;

and getDouble() returns null, it's equivalent to writing:

value = condition ? ((Double) null) : 1.0;

In this case the compiler sees a Double and a double as the 2nd and 3rd arguments of the ternary conditional operator, and decides that type of the expression should be double. Therefore it unboxes the null to double, getting NullPointerException.

The type of the conditional ternary operator is determined by some tables in JLS 15.25.

If the 2nd and 3rd operands are null and double, the conditional expression type is the least upper bound of Double and null, which is Double.

If the 2nd and 3rd operands are Double and double, the conditional expression type is double.

Short form for Java If statement returns NullPointerException when one of the returned objects is null

In the second case, the compiler can infer that the null must be a Long type. In the first case, it doesn't - and assumes that the expression returns a long. You can see that this is the case (i.e. fix it) like,

Long res = obj == null ? lNull : (Long) 10L;

which does not yield a NullPointerException.



Related Topics



Leave a reply



Submit