4

I am trying to understand the following code. Line number 2 outputs null while line 3 throws NullPointerException. What am I missing ? Theoretically it should work.

public static void main(String []args){

  1  Object[] obj = {null}; 
  2  System.out.println((Integer)obj[0]);  //Output null

  3  Integer n = obj[0] == null ? (Integer)obj[0] : 1; //NullPointerException
  4  System.out.println(n);
 }
Adeel
  • 413
  • 1
  • 7
  • 22
  • The use of an array and a cast to Integer adds extra noise to the code in terms of asking about the behaviour: `Integer num = null;` would be easier, and semantically equivalent. – Andy Turner Sep 18 '19 at 06:47

2 Answers2

9

Based on the rules defined in the JLS, the type of the ternary conditional operator

null ? (Integer)obj[0] : 1;

is int, not Integer.

Hence, when the result of this expression is (Integer)obj[0], the Integer is unboxed to int, and you get NullPointerException.

See JLS 15.25. Conditional Operator ? :, Table 15.25-A. :

Since your second operand is Integer and your third operand is int, the conditional expression type is int.

Eran
  • 387,369
  • 54
  • 702
  • 768
2

The key concept here is binary numeric promotion.

When you supply an operator with operands of different types, the operands have to be are converted to be compatible with one another. The conditional operator's rules for this conversion are reasonably complicated; but when the operands are of differing types, and are convertible to numbers, binary numeric promotion is applied.

In the case of supplying one boxed and one primitive operand, the effect of binary numeric promotion is to attempt to unbox the boxed operand, not to box the primitive operand.

You get can observe binary numeric promotion with other multi-operand operators, for example +:

System.out.println(1 + (Integer) null); // NullPointerException!

With the conditional operator, you would not get a NPE if you explicitly box the 1, because the operands are then not of differing types:

Integer n = obj[0] == null ? (Integer)obj[0] : Integer.valueOf(1);
Andy Turner
  • 137,514
  • 11
  • 162
  • 243