来自java.lang.Exception
类的javaDocs:
需要在方法或构造函数中声明已检查的异常 如果可以通过执行方法抛出它们,则抛出子句 构造函数并在方法或构造函数边界之外传播。
但请考虑以下代码:
package other;
public class CheckedExceptionHandling {
private static <E extends Exception> void throwException() throws E {
throw (E) new CheckedException2(); // unchecked cast warning
}
private static void setUncaughtExceptionHandler() {
Thread.currentThread().setUncaughtExceptionHandler((t, e) -> {
System.out.println("Unhandled exception: " + e.getClass()); // reports CheckedExceptionHandling$CheckedException2
});
}
public static void main(String[] args) /* no checked exceptions declared! */ {
setUncaughtExceptionHandler();
try {
CheckedExceptionHandling.<CheckedException1>throwException();
} catch (CheckedException1 e) {
System.out.println(e); // never gets here
}
}
// checked exceptions:
public static class CheckedException1 extends Exception {}
public static class CheckedException2 extends Exception {}
}
它会发出警告并且运行时结果为:
未处理的异常:class other.CheckedExceptionHandling $ CheckedException2
我预计运行时会发生编译时错误unreported exception CheckedException2; must be caught or declared to be thrown
或incompatible types: CheckedException2 cannot be converted to CheckedException1
或至少ClassCastException
。
但编译器允许将未检查的异常保留为未处理,未声明并在方法main
之外传播到未捕获的异常处理程序。
为什么?我在这里错过了什么吗?
答案 0 :(得分:0)
问题是编译器没有看过方法边界。在throwsException()中,除了“extends Exception”之外没有关于E的信息,因此编译器无法证明转换是错误的并且发出警告,而不是错误(正如Marko已在评论中指出的那样)。
在main()中,编译器只能看到“throwsException”的签名,它被定义为“throws E”,而在main()中,E是CheckedException。当CheckedException被捕获时,这里的一切都很好。
然后,Java在编译时抛弃所有泛型类型信息,因此在字节代码中不存在对E的强制转换。因此,运行时也无法检测到类型错误。
这里打破的不是异常处理,而是类型系统。