The first thing to keep in mind is that Java ternary operators have a "type", and that this is what the compiler will determine and consider no matter what the actual/real types of the second or third parameter are. Depending on several factors the ternary operator type is determined in different ways as illustrated in the Java Language Specification 15.26
In the question above we should consider the last case:
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).
This is by far the most complex case once you take a look at applying capture conversion (§5.1.10) and most of all at lub(T1, T2).
In plain English and after an extreme simplification we can describe the process as calculating the "Least Common Superclass" (yes, think of the LCM) of the second and third parameters. This will give us the ternary operator "type". Again, what I just said is an extreme simplification (consider classes that implement multiple common interfaces).
For example, if you try the following:
long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));
You'll notice that resulting type of the conditional expression is java.util.Date
since it's the "Least Common Superclass" for the Timestamp
/Time
pair.
Since null
can be autoboxed to anything, the "Least Common Superclass" is the Integer
class and this will be the return type of the conditional expression (ternary operator) above. The return value will then be a null pointer of type Integer
and that is what will be returned by the ternary operator.
At runtime, when the Java Virtual Machine unboxes the Integer
a NullPointerException
is thrown. This happens because the JVM attempts to invoke the function null.intValue()
, where null
is the result of autoboxing.
In my opinion (and since my opinion is not in the Java Language Specification many people will find it wrong anyway) the compiler does a poor job in evaluating the expression in your question. Given that you wrote true ? param1 : param2
the compiler should determine right away that the first parameter -null
- will be returned and it should generate a compiler error. This is somewhat similar to when you write while(true){} etc...
and the compiler complains about the code underneath the loop and flags it with Unreachable Statements
.
Your second case is pretty straightforward and this answer is already too long... ;)
CORRECTION:
After another analysis I believe that I was wrong to say that a null
value can be boxed/autoboxed to anything. Talking about the class Integer, explicit boxing consists in invoking the new Integer(...)
constructor or maybe the Integer.valueOf(int i);
(I found this version somewhere). The former would throw a NumberFormatException
(and this does not happen) while the second would just not make sense since an int
cannot be null
...
int foo = (true ? null : 0)
andnew Integer(null)
both compile fine, the second being the explicit form of autoboxing. – Buddenull
toInteger
... That would look just like "guessing" to me or "making things work"... – StenophyllousInteger foo() { return "1"; }
won't compile.) – Monroreturn (Integer)null;
compiles fine – Guttypublic void foo() { try { foo(); } finally { foo(); } }
being a nearly endless recursive function. – Browband