3

The following (logically) is a compile-time error:

public int myMethod(MyObject input) {
   if (input == null) {
     return null; // compiler says I cannot return null for primitive type
   } else {
     return 1;
   }
}

So far so good. What I don't understand, that the following is allowed:

public int myMethod(MyObject input) {
   return input == null ? null : 1;
}

Why? Recognising this should be straightforward for the compiler, or do I miss some crucial point here?

(And of course if in the ternary operator one ends up on the "null-branch", then it's a NPE, what else? :))

D. Kovács
  • 1,232
  • 13
  • 25

1 Answers1

2

The type of the ternary conditional operator is determined by the types of its 2nd and 3rd operands.

In the case of

input == null ? null : 1

the type is Integer, which can be assigned both null and 1.

The compiler allows your method to return an Integer since it can be auto-unboxed into an int, so it fit the int return type of myMethod.

The fact that your specific code may throw a NullPointerException is not something the compiler can detect.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • Can you please elaborate why compiler sees both the conditions differently? I mean in the first case it's detecting NPE, but in the second case it's not. It' detecting NPE, because the return statement is too simple, that is `return null`. Second case also seems identical. – 11thdimension Jun 12 '17 at 07:14
  • @11thdimension `null` cannot be converted automatically to a primitive type, so a method with an `int` return type cannot have a `return null;` statement. On the other hand, it can have a `return (Integer)null;` statement, since in that case you are returning an `Integer`, which can be auto-unboxed to an `int` (even though in this case it will always throw `NullPointerException` (in that case the compiler produces a warning, but the code passes compilation). – Eran Jun 12 '17 at 07:27
  • @Eran actually yes, the problem is, that in the ternary case, the compiler doesn't even produce a warning. With that I would be happy already. – D. Kovács Jun 12 '17 at 07:30
  • @D.Kovács That's because the ternary operator is not guaranteed to produce `NullPointerException`. It would return 1 if `input != null`. On the other hand, the expression `return (Integer) null;` would always produce a `NullPointerException` in a method that returns an `int`. – Eran Jun 12 '17 at 07:32
  • 1
    @Eran yes, but it _may_ return null. And actually if I add the explicit cast to the ternary as in `return input == null ? (Integer)null : 1;` then I get a compiler warning stating that I'm auto-unboxing a `null`. Without the explicit cast it could emit the same warning, couldn't it? – D. Kovács Jun 12 '17 at 07:38
  • I think the key is that ternary operator can return more than one type of value. As you mentioned type depends on the second and third operand. Your above comment doesn't make sense to me that "`return (Integer) null` will always produce NPE" as there can not multiple return statements in the same conditional branch, both conditions are equivalent in that their return statements occur in different branches. So first one doesn't always produce exception, as it's condition may be false just like the second one. – 11thdimension Jun 12 '17 at 07:39