我正在编译这个类:
public class Test {
// No throws clause here
public static void main(String[] args) {
doThrow(new SQLException());
}
static void doThrow(Exception e) {
Test.<Exception>doThrow0(e);
Test.doThrow0(e);
}
static <E extends Exception> void doThrow0(Exception e) throws E {
throw (E) e;
}
}
为什么
**Test.<Exception>doThrow0(e);**
这一行给出错误来指定 throws 子句(或将其包含在 try-catch 中)
并且 **Test.doThrow0(e);**
此行不会给出使用 throws 子句的任何错误
这是因为类型推断更喜欢尽可能推断出现在
throws
子句中的类型参数而不是未经检查的异常。
来自JLS 18.1.3:
在推理过程中,维护一组推理变量的界限。界限具有以下形式之一:
- ...
:推理变量 α 出现在throws α
子句中。throws
...
形式的界限纯粹是信息性的:它指导解析来优化 α 的实例化,以便在可能的情况下,它不是受检查的异常类型。throws α
在第一次尝试分辨率时,考虑了这个界限。
否则,如果边界集包含
,并且 αi 的每个真上界都是throws αi
的超类型,则 Ti =RuntimeException
。RuntimeException
在
Test.doThrow0(e)
中,没有任何内容表明 E
应该是受检异常,因此类型推断将其推断为 RuntimeException
,即未经受检异常。
如果
doThrow0
采用 E
作为参数,则会在参数类型和 doThrow0
抛出的异常类型之间建立关系。现在 E
将在调用 Exception
中被推断为 Test.doThrow0(e)
。
在
Test<Exception>doThrow0(e)
中,您明确指定 E
应该是受检查的异常。这里甚至不涉及类型推断。
另请参阅这个其他问题,您可以在其中找到需要“尝试不推断已检查异常”的示例。