Java 8中异常类型推断的一个特殊功能 [英] A peculiar feature of exception type inference in Java 8
问题描述
在本站点编写另一个答案的代码时,我遇到了这个特点:$ b
$ b pre $ static $ testSneaky(){
final Exception e = new Exception();
sneakyThrow(e); //这里没有问题
nonSneakyThrow(e); //错误:未处理的异常:java.lang.Exception
}
@SuppressWarnings(unchecked)
static< T extends Throwable> void sneakyThrow(Throwable t)抛出T {
throw(T)t;
}
static< T extends Throwable> void nonSneakyThrow(T t)抛出T {
throw t;
$ / code>
首先,我很困惑为什么 sneakyThrow
调用对编译器是可以的。当没有提及未经检查的异常类型的任何地方时,它推断出 T
有什么可能的类型?第二,接受这一点,为什么编译器会抱怨 nonSneakyThrow
调用?他们看起来非常相似。
推断 sneakyThrow
为 RuntimeException
。这可以从类型推断的语言规范( http ://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html )
首先,第18.1.3节:
lockquote
$ 形式的边界引发α
纯粹是信息性的:它指示解析来优化α的实例化,以便尽可能不是检查的异常类型。
不会影响任何东西,但它指向了解决方案部分(18.4),该部分获得了有关推断的异常类型的更多信息,其中包含特殊情况:
...否则,如果绑定集包含
则抛出αi
,并且αi的正确上限至多为Exception
,Throwable
和Object
,那么Ti =RuntimeException
。
这种情况适用于 sneakyThrow
- 唯一的上限是 Throwable
,所以根据规范推断 RuntimeException
所以它编译。该方法的主体是无关紧要的 - 未经检查的转换在运行时成功,因为它实际上并没有发生,留下的方法可以击败编译时检查异常系统。
nonSneakyThrow
不会编译为该方法的 T
的下限为异常 code>(即
T
必须是异常
的超类型,或异常
本身),这是一个检查的异常,由于它被调用的类型,所以 T
被推断为异常
。
While writing code for another answer on this site I came across this peculiarity:
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;
}
First, I am quite confused why the sneakyThrow
call is OK to the compiler. What possible type did it infer for T
when there is no mention anywhere of an unchecked exception type?
Second, accepting that this works, why then does the compiler complain on the nonSneakyThrow
call? They seem very much alike.
The T of sneakyThrow
is inferred to be RuntimeException
. This can be followed from the langauge spec on type inference (http://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html)
Firstly, there's a note in section 18.1.3:
A bound of the form
throws α
is purely informational: it directs resolution to optimize the instantiation of α so that, if possible, it is not a checked exception type.
This doesn't affect anything, but it points us to the Resolution section (18.4), which has got more information on inferred exception types with a special case:
... Otherwise, if the bound set contains
throws αi
, and the proper upper bounds of αi are, at most,Exception
,Throwable
, andObject
, then Ti =RuntimeException
.
This case applies to sneakyThrow
- the only upper bound is Throwable
, so T
is inferred to be RuntimeException
as per the spec, so it compiles. The body of the method is immaterial - the unchecked cast succeeds at runtime because it doesn't actually happen, leaving a method that can defeat the compile-time checked exception system.
nonSneakyThrow
does not compile as that method's T
has got a lower bound of Exception
(ie T
must be a supertype of Exception
, or Exception
itself), which is a checked exception, due to the type it's being called with, so that T
gets inferred as Exception
.
这篇关于Java 8中异常类型推断的一个特殊功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!