1

Clearly returning null for a boolean type is an error. Why doesn't javac catch this?

public class Test {
    public static void main(String[] args) {
        Object a = null;
        System.out.println(getThing(a));
    }

    private static boolean getThing(Object o) {
        return o == null ? null : Boolean.TRUE;
    }
}
macawm
  • 142
  • 1
  • 10
  • 3
    Possible duplicate of [Tricky ternary operator in Java - autoboxing](https://stackoverflow.com/questions/8098953/tricky-ternary-operator-in-java-autoboxing) – 11thdimension Jul 14 '17 at 19:14
  • This is also discussed here, but I didn't include autoboxing in my search so I didn't find it. [Java autoboxing and ternary operator madness](https://stackoverflow.com/questions/25417438/java-autoboxing-and-ternary-operator-madness) – macawm Jul 14 '17 at 19:28

1 Answers1

1

The question

Clearly returning null for a boolean type is an error. Why doesn't javac catch this?

Given that question, here's the relevant part of the code:

private static boolean getThing(Object o) {
    return o == null ? null : Boolean.TRUE;
}

That method includes a conditional expression (JLS 15.25) where:

  1. the first expression is o == null
  2. the second expression is null
  3. the third expression is Boolean.TRUE

Why it compiles

The reason javac allows it is:

  • The conditional expression is classified as a reference conditional expression (JLS 15.25.3) due to the second and third expressions "null" and "Boolean.TRUE", excerpted from JLS 15.25:

    If both the second and the third operand expressions are boolean expressions, the conditional expression is a boolean conditional expression.

    If both the second and the third operand expressions are numeric expressions, the conditional expression is a numeric conditional expression.

    Otherwise, the conditional expression is a reference conditional expression.

  • The entire conditional expression is classified as type java.lang.Boolean

  • The conditional expression is of reference type Boolean, and the method return type – primitive "boolean" – can be unboxed from Boolean

The compiler kind of "allowing" a code path where "null" might be unboxed to "boolean" isn't all that different from various other obvious programming errors.

For example, here's code that creates a new object, gives it a value of null, then tries to invoke a method on that object. This code compiles fine but, unsurprisingly, throws an exception at runtime:

Object o = null;
System.out.println(o.hashCode());

Exception in thread "main" java.lang.NullPointerException:
Cannot invoke "Object.hashCode()" because "o" is null

It compiles, but doesn't run

Though your code compiles, the following exception is thrown at runtime when null is unboxed to boolean:

Exception in thread "main" java.lang.NullPointerException:
Cannot invoke "java.lang.Boolean.booleanValue()"

While the return value of the statement is null – a valid value for Boolean – unboxing to a boolean primitive (to line up with the method return type) throws an exception. Unboxing tries to call null.booleanValue() which won't work.

You weren't asking, but – an easy fix would be to change the return type of the method from primitive boolean to Boolean. After doing that, your program compiles and runs, printing "null" (from System.out.println(getThing(a)).

Kaan
  • 5,434
  • 3
  • 19
  • 41