Mar*_*nik 83 java generics type-inference java-8
在本网站上为另一个答案编写代码时,我遇到了这样的特点:
static void testSneaky() {
final Exception e = new Exception();
sneakyThrow(e); //no problems here
nonSneakyThrow(e); //ERRROR: Unhandled exception: java.lang.Exception
}
@SuppressWarnings("unchecked")
static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
throw (T) t;
}
static <T extends Throwable> void nonSneakyThrow(T t) throws T {
throw t;
}
Run Code Online (Sandbox Code Playgroud)
首先,我很困惑为什么sneakyThrow对编译器调用是好的.T在没有提到未经检查的异常类型的任何地方时,它推断出什么可能的类型?
其次,接受这是有效的,为什么编译器会在nonSneakyThrow电话中抱怨?它们看起来非常相像.
the*_*oop 64
T sneakyThrow被推断为RuntimeException.这可以从类型推断的语言规范(http://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html)开始.
首先,第18.1.3节有一个注释:
表单的边界
throws ?纯粹是信息性的:它指示解析以优化α的实例化,以便在可能的情况下,它不是经过检查的异常类型.
这不会影响任何事情,但它指向了解决方案部分(18.4),它提供了有关特殊情况的推断异常类型的更多信息:
......否则,如果绑定集包含
throws ?i,和α我的正常上限的,顶多Exception,Throwable和Object,然后TI =RuntimeException.
这种情况适用于sneakyThrow- 唯一的上限是Throwable,所以T推断是RuntimeException按照规范,所以它编译.该方法的主体是无关紧要的 - 未经检查的转换在运行时成功,因为它实际上不会发生,留下一个方法可以打败编译时检查的异常系统.
nonSneakyThrow不编译,因为该方法的T下限Exception(即T必须是超类型Exception或其Exception本身),这是一个经过检查的异常,因为它被调用的类型,因此T被推断为Exception.
Zho*_*gYu 17
如果类型推断为类型变量生成单个上限,则通常选择上限作为解.例如,如果T<<Number,解决方案是T=Number.虽然Integer,Float等,也能满足约束条件,没有充分的理由选择了他们Number.
throws T在java 5-7中也是如此:T<<Throwable => T=Throwable.(偷偷摸摸的抛出解决方案都有明确的<RuntimeException>类型参数,否则<Throwable>推断出来.)
在java8中,随着lambda的引入,这就成了问题.考虑这种情况
interface Action<T extends Throwable>
{
void doIt() throws T;
}
<T extends Throwable> void invoke(Action<T> action) throws T
{
action.doIt(); // throws T
}
Run Code Online (Sandbox Code Playgroud)
如果我们用空的lambda调用,那么T推断为什么?
invoke( ()->{} );
Run Code Online (Sandbox Code Playgroud)
唯一的约束T是上限Throwable.在java8的早期阶段,T=Throwable将推断出来.见我提交的这份报告.
但这是非常愚蠢的Throwable,从空块中推断出一个经过检查的异常.报告中提出了一个解决方案(显然是由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)
Run Code Online (Sandbox Code Playgroud)
即如果上限是Exception或Throwable,则选择RuntimeException作为解决方案.在这种情况下,是一个很好的理由来选择上限的特定亚型.