1

我知道如果java找到了保证控制永远不会到达的代码行,那么编译器会报告无法访问的代码错误。
考虑以下代码。

    static int method1() {

        try{ return 1; }
        catch(Exception e){ }  // LINE-1
        finally{ }
        System.out.println("abc");  //LINE-2
        return 2;
    }
}

在上面的代码中,
1 try 块通过返回 1 来保证退出,但在 finally 块(LINE-2 之后)之后仍然可以访问。
2 . 如果我评论 catch 块 (LINE-1),则 LINE-2 变得无法访问。

为什么会这样。编译器不能在 case-1 的 try 块中看到无条件返回。

4

4 回答 4

7

这是JLS 14.21的相关部分:

如果try以下两个都为真,则语句可以正常完成:

  • try块可以正常完成或任何catch块都可以正常完成。

  • 如果try语句有finally块,则该finally块可以正常完成。

在这种情况下,虽然你的 try 块不能正常完成,但它有一个可以正常完成的 catch 块。finally 块也可以正常完成。

try语句是可达的,可以正常完成,因此它后面的语句是可达的。

如果您删除该catch块,则上面引用的部分中的第一个项目符号不再是正确的 - 这意味着该try语句无法正常完成,并且它后面的语句无法访问。

于 2016-08-18T16:48:19.000 回答
3

一个try块(好吧,带有 acatch)告诉编译器“这里的内容可能会导致异常”。因此编译器假定,即使return其中有语句,该try也可能不会成功返回。

鉴于该假设,存在到达catch和 的逻辑路径finally。并且由于这些都没有返回,相同的逻辑路径将try/catch/finally完全结束整个过程并导致到达它之后的代码。

基本上,编译器(好吧,其设计者)更喜欢简单的规则而不是复杂的规则。简单的规则更容易测试和支持,并且向后兼容未来的版本。因此,对于一个更彻底地分析逻辑的人来说,不可能到达那个代码,但对于编译器来说,这是完全可能的。

于 2016-08-18T16:45:52.093 回答
1

编译器看到你有一个catchException并假设它有可能发生(因为你告诉它它可以)。由于在finally之后是可访问的catch,因此它后面的代码也是如此(因为该catch块不执行任何终止函数的操作,也不执行finally)。在您注释掉 的catch那一刻,编译器就知道它在任何情况下都不会超过 finally,因此会出现错误。

于 2016-08-18T16:45:11.207 回答
1

您无需考虑 try 块中的 return 语句,而是考虑 try 块本身。它看到 try 块并要求 catch 在那里(可选地,它可以有一个 finally 块)。如果你删除了 catch 语句,try 块不知道如果发生错误该怎么办,所以它下面的任何东西都不会被访问(因此是无法访问的代码错误)

编译器认为“好吧,如果 try 块确实输出错误,这段代码会发生什么 - 好吧,它下面的代码不会执行,因为我没有被告知如何从该错误中恢复”

当你有一个 catch 语句时,编译有点像 - 我会尝试“CODE HERE”,如果出错,我将捕获错误并执行“CODE HERE”,并且可选地我最终会执行“CODE HERE”。然后我将像往常一样在块下方执行。

于 2016-08-18T16:56:40.163 回答