捕获并重新抛出异常,但这不是异常

时间:2019-10-16 15:03:17

标签: java exception throws

我偶然发现了看起来像这样的代码:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() {
    throw new RuntimeException();
}

此代码使我感到惊讶,因为它看起来run()方法能够抛出Exception,因为它捕获了Exception然后将其重新抛出,但是该方法未声明为抛出Exception,显然不需要。这段代码可以很好地编译(至少在Java 11中)。

我的期望是我将不得不在throws Exception方法中声明run()

其他信息

以类似的方式,如果doSomething被声明抛出IOException,则IOException方法中只需要声明run(),即使{{1} }被捕获并重新抛出。

Exception

问题

Java通常喜欢清晰,这种行为背后的原因是什么?一直都是这样吗? Java语言规范中的哪些内容允许void run() throws IOException { try { doSomething(); } catch (Exception ex) { System.out.println("Error: " + ex); throw ex; } } void doSomething() throws IOException { // ... whatever code you may want ... } 方法无需在上面的代码段中声明run()? (如果我要添加它,IntelliJ会警告我永远不要抛出throws Exception。)

1 个答案:

答案 0 :(得分:0)

我没有按照您在问题中的要求浏览JLS,所以请带着一点盐来回答这个问题。我想发表评论,但那可能太大了。


我有时觉得很有趣,javac在某些情况下(例如您的情况)是多么“聪明”,但是还有很多其他事情需要稍后JIT处理。在这种情况下,只是编译器“知道”只会捕获RuntimeException。这很明显,这是您丢进doSomething中的唯一东西。如果您将代码稍微更改为:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

您会看到不同的行为,因为现在javac可以告诉您有一个新的Exception与您所捕获的对象无关。

但是事情远非理想,您可以通过以下方式再次“欺骗”编译器:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        ex2 = ex;
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

IMO,由于ex2 = ex;,它不应再次失败,但是会失败。

如果是使用javac 13+33编译的,则