为什么在这种情况下允许抛出已检查的异常类型?

Boa*_*ann 16 java exception throw language-lawyer checked-exceptions

我偶然注意到这个throw语句(从一些更复杂的代码中提取)编译:

void foo() {
    try {

    } catch (Throwable t) {
        throw t;
    }
}
Run Code Online (Sandbox Code Playgroud)

对于一个短暂而快乐的时刻,我认为已经检查过的异常最终决定已经死了,但它仍然在这方面很高兴:

void foo() {
    try {

    } catch (Throwable t) {
        Throwable t1 = t;
        throw t1;
    }
}
Run Code Online (Sandbox Code Playgroud)

try块不必为空; 它似乎可以有代码,只要该代码不会抛出已检查的异常.这似乎是合理的,但我的问题是,语言规范中的哪些规则描述了这种行为?据我所知,§14.18town语句明确禁止它,因为t表达式的类型是一个已检查的异常,并且它没有被捕获或声明被抛出.(?)

Kep*_*pil 13

这是因为Java 7中引入的Project Coin中包含的更改允许通过重新抛出原始异常来进行常规异常处理.这是一个适用于Java 7但不适用于Java 6的示例:

public static demoRethrow() throws IOException {
    try {
        throw new IOException("Error");
    }
    catch(Exception exception) {
        /*
         * Do some handling and then rethrow.
         */
        throw exception;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处阅读解释更改的整篇文章.

  • 但是表达式类型是`Throwable`并且不能"赋值"到`RuntimeException`或`Error`,因为这需要一个强制转换,它似乎是§5.5,而不是§5.2. (2认同)

rua*_*akh 8

我认为,在措辞§14.18的throw声明,你指的是在JLS一个错误-应该已经更新了Java SE 7中,而不是文字.

描述预期行为的JLS文本位于第11.2.2节语句的异常分析中:

throw,其抛出的表达式语句是最终或有效决赛异常参数catch根据条款C可以抛出一个异常,E级IFF:

  • E是一个异常类,声明C trytry语句块可以抛出; 和
  • E的赋值与C的任何可捕获异常类兼容; 和
  • E与赋值catch在同一try语句中C的左侧的子句的任何可捕获异常类不兼容.

第一个要点是相关要点; 因为catch-clause参数t实际上是最终的(意味着它从未被赋值或递增或递减;参见§4.12.4 final变量),throw t只能抛出try块可以抛出的东西.

但正如您所说,§14.18中的编译时检查不会对此作出任何限制.§11.2.2不决定允许什么,不允许什么; 相反,它应该是对可以抛出的各种限制的后果的分析.(这种分析确实反馈到规范的更规范的部分 - §14.18本身在其第二个子弹点中使用它 - 但§14.18不能只说"如果它抛出一个它不能的例外它是一个编译时错误抛出§11.2.2",因为这将是循环的.)

所以我认为需要调整§14.18以适应§11.2.2的意图.

很好找!