Booleans, Conditional Operators and Autoboxing

Booleans, conditional operators and autoboxing

The difference is that the explicit type of the returnsNull() method affects the static typing of the expressions at compile time:

E1: `true ? returnsNull() : false` - boolean (auto-unboxing 2nd operand to boolean)

E2: `true ? null : false` - Boolean (autoboxing of 3rd operand to Boolean)

See Java Language Specification, section 15.25 Conditional Operator ? :

  • For E1, the types of the 2nd and 3rd operands are Boolean and boolean respectively, so this clause applies:

    If one of the second and third operands is of type boolean and the type of the other is of type Boolean, then the type of the conditional expression is boolean.

    Since the type of the expression is boolean, the 2nd operand must be coerced to boolean. The compiler inserts auto-unboxing code to the 2nd operand (return value of returnsNull()) to make it type boolean. This of course causes the NPE from the null returned at run-time.

  • For E2, types of the 2nd and 3rd operands are <special null type> (not Boolean as in E1!) and boolean respectively, so no specific typing clause applies (go read 'em!), so the final "otherwise" clause applies:

    Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).

    • S1 == <special null type> (see §4.1)
    • S2 == boolean
    • T1 == box(S1) == <special null type> (see last item in list of boxing conversions in §5.1.7)
    • T2 == box(S2) == `Boolean
    • lub(T1, T2) == Boolean

    So the type of the conditional expression is Boolean and the 3rd operand must be coerced to Boolean. The compiler inserts auto-boxing code for the 3rd operand (false). The 2nd operand doesn't need the auto-unboxing as in E1, so no auto-unboxing NPE when null is returned.


This question needs a similar type analysis:

Java conditional operator ?: result type

Java auto boxing/unboxing wierdness

From section 15.25 of the Java Language Specification:

The type of a conditional expression is determined as follows:

  • If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.
    • If one of the second and third operands is of type boolean and the type of the other is of type Boolean, then the type of the conditional expression is boolean.
    • If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.
    • Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:
      • If one of the operands is of type byte or Byte and the other is of type short or Short, then the type of the conditional expression is short.
      • If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression of type int whose value is representable in type T, then the type of the conditional expression is T.
      • If one of the operands is of type Byte and the other operand is a constant expression of type int whose value is representable in type byte, then the type of the conditional expression is byte.
      • If one of the operands is of type Short and the other operand is a constant expression of type int whose value is representable in type short, then the type of the conditional expression is short.
      • If one of the operands is of type; Character and the other operand is a constant expression of type int whose value is representable in type char, then the type of the conditional expression is char.
      • Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands. Note that binary numeric promotion performs unboxing conversion (§5.1.8) and value set conversion (§5.1.13).

So it's following the final bullet, performing binary numeric promotion, which performs an unboxing conversion. So the type of the conditional operator expression is int, even though you're assigning it to an Integer. It's trying to perform the unboxing conversion on null, hence the exception.

Why wrapped type unboxed instead of boxing the primitive?

Consider this scenario:

 Boolean b1 = new Boolean(false); //I know you shouldn't be doing this but it's valid
boolean foo = b1 == false;
Boolean bar = b1 == false;

Now if things worked like you probably expect them to be, foo would be true and bar would be false. Or, alternatively both could be false but that would mean autoboxing everything all the time if just a single boxed primitive occurs in the expression. (And then potentially unboxing it for the assignment.)

I wouldn't consider that a good trade-off. Granted, dealing with NPEs from unboxing conversions is ugly but it's something you have to do anyway in most unboxing scenarios.

Booleans, conditional operators and autoboxing

The difference is that the explicit type of the returnsNull() method affects the static typing of the expressions at compile time:

E1: `true ? returnsNull() : false` - boolean (auto-unboxing 2nd operand to boolean)

E2: `true ? null : false` - Boolean (autoboxing of 3rd operand to Boolean)

See Java Language Specification, section 15.25 Conditional Operator ? :

  • For E1, the types of the 2nd and 3rd operands are Boolean and boolean respectively, so this clause applies:

    If one of the second and third operands is of type boolean and the type of the other is of type Boolean, then the type of the conditional expression is boolean.

    Since the type of the expression is boolean, the 2nd operand must be coerced to boolean. The compiler inserts auto-unboxing code to the 2nd operand (return value of returnsNull()) to make it type boolean. This of course causes the NPE from the null returned at run-time.

  • For E2, types of the 2nd and 3rd operands are <special null type> (not Boolean as in E1!) and boolean respectively, so no specific typing clause applies (go read 'em!), so the final "otherwise" clause applies:

    Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).

    • S1 == <special null type> (see §4.1)
    • S2 == boolean
    • T1 == box(S1) == <special null type> (see last item in list of boxing conversions in §5.1.7)
    • T2 == box(S2) == `Boolean
    • lub(T1, T2) == Boolean

    So the type of the conditional expression is Boolean and the 3rd operand must be coerced to Boolean. The compiler inserts auto-boxing code for the 3rd operand (false). The 2nd operand doesn't need the auto-unboxing as in E1, so no auto-unboxing NPE when null is returned.


This question needs a similar type analysis:

Java conditional operator ?: result type

Why does returning null (where a boolean is expected) as the result of a ternary operator compile?

As the jls states:

The type of a conditional expression is determined as follows:
If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.
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 (§5.1.7) to T, then the type of the conditional expression is T.

This means java allows null, since it can be used to generate an instance of Boolean, which can be unboxed to boolean (read the section about boxing in the jls for more info). But since the Boolean instance is initialized null, the call to booleanValue() will result in a NullPointerException.

Unwanted autoboxing magic on Numbers

Let's take out the language lawyer's book here: JLS §15.25

The type of a conditional expression is determined as follows:

  • If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.

Long and Double are not the same type - does not apply.

  • 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
    (§5.1.7) to T, then the type of the conditional expression is T.

Neither value is primitive - does not apply.

  • If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the
    conditional expression is that reference type.

Neither value is null - does not apply.

  • Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:

    • [... special cases for byte/short/char and their boxed equivalents...]
    • Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.

This rule does apply here, which means that the result type of the conditional operator is as if both values were unboxed. Is suppose the reasoning behind that was that otherwise Number n = bool ? 1 : 2.0 and Number n = bool ? new Long(1) : new Double(2.0) have different values. This behaviour would also be unexpected and - worse - inconsistent.

Autoboxing not working?

Have a look at this bug report which was closed as Not an Issue citing the below reason.

Autoboxing of entire arrays is not specified behavior, for good
reason. It can be prohibitively expensive for large arrays.

Therefore, to convert your array to an list, you need to do this

List<Integer> test = new ArrayList<Integer>(S.length);
for (int i : S) {
test.add(i);
}


Related Topics



Leave a reply



Submit