Java: the ternary operator, the nuances of its operation


Let's have the following code:

System.out.print((true ? 1 : null).getClass().getSimpleName());

Everything will compile and the result will be

Integer

Getting into the documentation on the ternary operator, we have:

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.

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 (§15.28) 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 T, where T is Byte, Short, or Character, and the other operand is a constant expression (§15.28) of type int whose value is representable in the type U which is the result of applying unboxing conversion to T, then the type of the conditional expression is U.

  • 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 value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).

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).

Source

I have highlighted in bold two items that I think may be relevant to what is happening in the example. The question is, what exactly is happening and how in this case?

The first highlighted item - type compiler tries to apply these rules, sees that one of the operands is null.. but the second one is int, let me auto-pack it and it will be a reference type. And thus, the resulting type by the rule becomes Integer.

But why then the moment "let me auto-pack it and it will be a reference type" is not specified in the rule? Maybe this is implied, since this behavior is described elsewhere?

Or does the second highlighted rule still apply here? Honestly, I haven't figured it out yet, there is quite a lot of reading material and several times you need to jump through the links in the process of understanding, it will not be fast. Namely, what is "capture conversation" and " lub(T1, T2)".

But I can no longer understand, we have that S1 = = int type, S2 = = null type, then T1 == Integer, but what then with null and what is T2? I.e. it turns out that this rule does not apply.

I wonder what exactly is going on here?

Author: Дух сообщества, 2018-04-12

2 answers

The fact is that the ternary operator selects the type from the runtime depending on the condition. Therefore, the corresponding type formation is performed on the original expression. Since you have true in the expression, the second operand is simply not used and type conversion is not performed.

But I can no longer understand, we have that S1 = = int type, S2 == null type, then T1 == Integer, but what then with null and what is T2? I.e. it turns out that this rule is not applicable.

That's right, because the rule uses both expressions, and you have one.

 1
Author: Roman C, 2018-04-12 14:21:26

Second, logically and experimentally, because

System.out.print((true ? 1 : new Object()).getClass().getSimpleName());

Also outputs Integer

Updated:

    System.out.println((true ? 1 : null).getClass().getSimpleName());
    System.out.println((true ? 1 : new Object()).getClass().getSimpleName());
    System.out.println((false ? 1 : new Object()).getClass().getSimpleName());
    System.out.println((true ? 1 : new String()).getClass().getSimpleName());
    System.out.println((false ? 1 : new String()).getClass().getSimpleName());

=>
Integer
Integer
Object
Integer
String
 1
Author: Ramiz, 2018-04-12 14:26:26