48

While executing the following code, I am getting a NullPointerException at line:

value = condition ? getDouble() : 1.0;

In earlier lines when I use null instead of getDouble() everything works and this is strange.

public class Test {
    static Double getDouble() {
        return null;
    }

    public static void main(String[] args) {
        boolean condition = true;
        Double value;

        value = condition ? null : 1.0;         //works fine
        System.out.println(value);              //prints null

        value = condition ? getDouble() : 1.0;  //throws NPE
        System.out.println(value);
    }
}

Can someone help me understand this behavior?

T-Bag
  • 10,916
  • 3
  • 54
  • 118
  • 1
    What do you mean "change getDouble() to null"? The method already returns null in the code you posted. – OH GOD SPIDERS Sep 03 '18 at 09:51
  • This is the strange thing...If I change to null every thing works fine. Although method is returning null – T-Bag Sep 03 '18 at 09:52
  • 2
    When I say change to null means ...instead of calling the method which is returning null i used null directly – T-Bag Sep 03 '18 at 09:54
  • 3
    Possibly related: [Tricky ternary operator in Java - autoboxing](https://stackoverflow.com/q/8098953) – Pshemo Sep 03 '18 at 10:37
  • 3
    I tried to simplify and at the same time clarify your example. If I misunderstood your intention feel free to rollback my edit. – Pshemo Sep 03 '18 at 11:31
  • this question appears to be derived from [JDK-8062801](https://bugs.openjdk.java.net/browse/JDK-8062801) – gnat May 07 '19 at 06:17
  • And I think, Joker, you're a doppelganger of @Eran. Again: respect. – Curiosa Globunznik Dec 04 '19 at 10:15

2 Answers2

78

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.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • 8
    Weird. I'd file some kind of ticket against this. Even if the language standard says the compiler is supposed to pick `double`, this is a narrowing conversion since `double` doesn't support `null`. All other implicit narrowing conversions are avoided like the plague, if I recall correctly. I should think it ought to be changed for consistency. – jpmc26 Sep 03 '18 at 20:14
  • based on the answer above ...you can change it to the following and it will work fine `value = condition ? getDouble() : new Double(1.0);` – rohit thomas Sep 04 '18 at 03:11
  • Why would someone know that? – ozgur Sep 27 '18 at 22:23
26

See #jls-15.25:

enter image description here

If the 2nd operand is Double, while the 3rd operand is double, the result:

getCount() == 1 ? getDouble() : 1.0

will be a double.

And when you try to convert a Double null(returned by getDouble()) to double, NPE will be thrown.

xingbin
  • 27,410
  • 9
  • 53
  • 103
  • 1
    And further on JLS: 15.25.2 says: "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 to `T`, then the type of the conditional expression is `T`." The boxing fails with a NPE. – LuCio Sep 03 '18 at 10:03