If type inference creates a single upper bound for a type variable, usually the upper bound is chosen as the solution. For example, if T<<Number , the solution is T=Number . Although Integer , Float , etc. They can also satisfy the restriction; there is no good reason to choose them by Number .
This was also the case with throws T in java 5-7: T<<Throwable => T=Throwable . (Sneaky throw solutions all had explicit arguments of type <RuntimeException> , otherwise <Throwable> .)
In java8 with the introduction of lambda, this becomes problematic. Consider this case
interface Action<T extends Throwable> { void doIt() throws T; } <T extends Throwable> void invoke(Action<T> action) throws T { action.doIt();
If we refer to an empty lambda, what would T output as?
invoke( ()->{} );
The only limit on T is the upper bound of Throwable . In the early stages of java8, T=Throwable would be inferred. See This Report I Submitted.
But it's pretty stupid to Throwable , an exception thrown from an empty block. The report suggested a solution (which, apparently, was taken 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<<X, if X:>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 , select RuntimeException as the solution. In this case, there is good reason to choose a specific subtype of the upper bound.
ZhongYu Jul 09 '15 at 20:18 2015-07-09 20:18
source share