javatypescastingconditional-operator

Why does the conditional (ternary) operator (? :) in Java perform type casting?


I've been experimenting with the ternary operator (? :) in Java and noticed that it automatically performs type casting on its expressions. For example, this code returns 2.0 instead of 2:

System.out.println(false ? 1.0 : 2);

In a regular if-else conditional, Java obviously doesn't perform type casting in the same way, but with the ternary operator, it does.

To determine the resulting type, I used the getClass() method for cases like differentiating between int and byte. For float or double versus int, the difference is obvious, as values like 2 become 2.0.

This raises a couple of questions:

  1. Why does the Java ternary operator perform type conversion in the first place?

  2. The operator seems to follow a typical Java type promotion hierarchy (e.g., byte -> short -> int -> long -> float). However, when int is involved, it always returns the other type if the int fits within the range of that type. For example, in the code below, the result is a byte with the value of 1:

System.out.println(true ? (int) 1 : (byte) 2);

This also applies to short in similar scenarios.

I haven't tested all possible type combinations with the ternary operator, but sometimes the type casting behavior seems inconsistent or arbitrary.

How does Java decide which type to return in these cases?


Solution

  • How does Java decide which type to return in these cases?

    The type of a ternary conditional expression is specified in Java Language Specification section 15.25. In this specific case, it is a numeric conditional expression, so the relevant subsection is 15.25.2.

    Your observation of

    when int is involved, it always returns the other type if the int fits within the range of that type.

    is basically correct. Here is what the spec says, in more precise terms

    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.29) of type int whose value is representable in type T, then the type of the conditional expression is T.

    The primitive wrappers work similarly, but the resulting type is the primitive type, rather than the wrappers.

    If one of the operands is of type T, where T is Byte, Short, or Character, and the other operand is a constant expression 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.

    So the type of someBoolean ? (int)1 : (Byte)2 is byte, not Byte.

    Also note

    If the second and third operands have the same type, then that is the type of the conditional expression.

    This is a significant difference from how regular numeric promotion works with arithmetic operators and so on.

    There are a few more rules regarding boxing, and promotion to short. For everything else, regular numeric promotion rules apply.