While writing code for another answer on this site I came across this peculiarity:
static void testSneaky() {
final Exception e = new Exception();
sneaky
If type inference produces a single upper bound for a type variable, typically the upper bound is chosen as the solution. For example, if T<T=Number. Although Integer, Float etc. could also satisfy the constraint, there's no good reason to choose them over Number.
That was also the case for throws T in java 5-7: T<. (Sneaky throw solutions all had explicit type arguments, otherwise is inferred.)
In java8, with the introduction of lambda, this becomes problematic. Consider this case
interface Action
{
void doIt() throws T;
}
void invoke(Action action) throws T
{
action.doIt(); // throws T
}
If we invoke with an empty lambda, what would T be inferred as?
invoke( ()->{} );
The only constraint on T is an upper bound Throwable. In earlier stage of java8, T=Throwable would be inferred. See this report I filed.
But that is pretty silly, to infer Throwable, a checked exception, out of an empty block. A solution was proposed in the report (which is apparently adopted by JLS) -
If E has not been inferred from previous steps, and E is in the throw clause,
and E has an upper constraint E<RuntimeException, infer E=RuntimeException
otherwise, infer E=X. (X is an Error or a checked exception)
i.e. if the upper bound is Exception or Throwable, choose RuntimeException as the solution. In this case, there is a good reason to choose a particular subtype of the upper bound.