4

In Java when I write like this

public int method(boolean b) {
    if (b)
        return null;
    else
        return 0;
}

the compiler complains incompatible types, but if substitute this with shorthand

public int method(boolean b) {
    return (b ? null : 0);
}

the compiler doesn't complain, moreover there will be a NPE. So my questions are

  1. Why compiler doesn't complain
  2. Why NPE?
Anirban Nag 'tintinmj'
  • 5,572
  • 6
  • 39
  • 59
  • 1
    2. The NPE because Integer.intValue() is called on null. The primitive type int can not be null, – Jens Jan 19 '15 at 16:01

2 Answers2

7

This is caused by a combination of auto-unboxing, and type inference.

In both cases, it is clear from the type signature that the method must return an int.

In your first case, you are explicitly returning null, which is not assignable to int, so the compiler rightly complains that this is an error.

In the second case, you're creating an anonymous value (the bit in the brackets), and so the compiler must infer the type of it. It works out that the most specific common supertype of 0 and null is Integer - which is correct. Therefore, your return statement is returning something of type Integer - and this is compatible with int, it just gets auto-unboxed at runtime. It is this auto-unboxing that throws the NPE, when the VM attempts to convert a null reference into an int.

If it helps you to visualise it better, your second example is essentially the same as:

public int method(boolean b) {
    Integer tmp = (b ? null : 0);
    return tmp;
}

and so the compiler has nothing to complain about (both lines are fine on their own).

The fault here, if there is one, is with auto-unboxing, and silently pretending that Integer is the same type as int. It isn't, for exactly this reason.

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
  • Ah, that explains why `return (Integer) null;` in the first example makes the compile error go away, but leaves the NPE at runtime. – azurefrog Jan 19 '15 at 16:03
  • More like `return tmp.intValue()`. – OldCurmudgeon Jan 19 '15 at 16:05
  • @OldCurmudgeon `return tmp;` works fine, you don't need the explicit `intValue()` call since Java will auto-unbox it without complaining. – azurefrog Jan 19 '15 at 16:07
  • @azurefrog - Correct - but it demonstrates more clearly where the NPE is coming from. – OldCurmudgeon Jan 19 '15 at 16:07
  • The 2nd case is not to do with "an anonymous value". The [ternary operator rule](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25) used is: "*one of the 2nd/3rd operands is of primitive type T, and the type of the other is the result of applying boxing conversion to T, then the type ... is T*": therefore it evaluates the ternary's result as `int` which is ok to return (§14.17) as it is assignable to `int`. This is why the method compiles. The bytecode is then compiled as `Integer.intValue()null` (and sadly box and then unbox 0), which throws the NPE at runtime. – Andy Brown Jan 19 '15 at 17:46
-1

The problem is the type that you want to return. You can't assign null to a primitive type. It's an half answer I don't know why it doesn't complain in the shorthand version.

ElPysCampeador
  • 399
  • 1
  • 4
  • 14