java – 为什么捕获检查异常允许不抛出异常的代码?

在抛出检查异常(Exception或其子类型 – IOException,InterruptedException等)的Java方法中,必须声明throws语句:

public abstract int read() throws IOException;

不声明throws语句的方法不能抛出检查异常。

但这是合法的java:

public void safeMethod() { System.out.println("I'm safe"); }

public void test() { // guarantees not to throw checked exceptions
    try {
        safeMethod();
    } catch (Exception e) { // catching checked exception
        throw e; // so I can throw... a checked Exception?
    }
}

其实,没有。这有点有趣:编译器知道e不是一个检查的异常,允许重新抛出它。事情甚至有点可笑,这段代码不编译:

public void test() { // guarantees not to throw checked exceptions
    try {
        safeMethod();
    } catch (Exception e) {        
        throw (Exception) e; // seriously?
    }
}
// Error: unreported exception java.lang.Exception; must be caught or declared to be thrown

第一个片段是一个问题的动机。

应该不应该编译器允许只捕获unchecked异常(RuntimeException和子类型)在这个catch子句 – 因为它知道被检查的异常(异常和子类型)不能抛出?

回到主要问题 – 是否有任何理由以这种方式实现捕获检查异常?这只是设计中的缺陷,还是我缺少一些重要因素 – 可能是后向不兼容?如果只允许RuntimeException在这种情况下被捕获,可能会出错?非常感谢。

最佳答案
报价Java Language Specification, §11.2.3

It is a compile-time error if a catch clause can catch checked exception class E1 and it is not the case that the try block corresponding to the catch clause can throw a checked exception class that is a subclass or superclass of E1, unless E1 is Exception or a superclass of Exception.

我猜这个规则早在Java 7之前就已经发生,在那里多重捕获不存在。因此,如果你有一个try块可以抛出许多异常,捕捉一切的最简单的方法是捕获一个共同的超类(在最坏的情况下,异常,或Throwable如果你想捕获错误)。

请注意,您可能无法捕获与实际抛出的内容完全无关的异常类型 – 在您的示例中,捕获不是RuntimeException的Throwable的任何子类将是一个错误:

try {
    System.out.println("hello");
} catch (IOException e) {  // compilation error
    e.printStackTrace();
}

编辑OP:答案的主要部分是问题示例只适用于Exception类的事实。通常在代码的随机位置中不允许捕获检查的异常。对不起,如果我困惑某人使用这些例子。

转载注明原文:java – 为什么捕获检查异常允许不抛出异常的代码? - 代码日志