Java检查的异常处理是否已损坏?

时间:2016-10-06 12:59:50

标签: java exception-handling

来自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 thrownincompatible types: CheckedException2 cannot be converted to CheckedException1或至少ClassCastException
编译器允许将未检查的异常保留为未处理,未声明并在方法main之外传播到未捕获的异常处理程序。 为什么?我在这里错过了什么吗?

1 个答案:

答案 0 :(得分:0)

问题是编译器没有看过方法边界。在throwsException()中,除了“extends Exception”之外没有关于E的信息,因此编译器无法证明转换是错误的并且发出警告,而不是错误(正如Marko已在评论中指出的那样)。

在main()中,编译器只能看到“throwsException”的签名,它被定义为“throws E”,而在main()中,E是CheckedException。当CheckedException被捕获时,这里的一切都很好。

然后,Java在编译时抛弃所有泛型类型信息,因此在字节代码中不存在对E的强制转换。因此,运行时也无法检测到类型错误。

这里打破的不是异常处理,而是类型系统。