无法访问的代码 - try-catch-finally

Unreachable code- try-catch-finally

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

    static int method1() {

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

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

为什么会这样。编译器无法在 case-1 的 try 块中看到无条件的 return。

编译器看到您有一个 Exceptioncatch 块,并假设它有可能发生(因为您告诉它可以)。由于 finallycatch 之后是可访问的,它后面的代码也是如此(因为 catch 块没有终止函数, [=12= 也没有]).当您注释掉 catch 时,编译器知道它在任何情况下都不会超过 finally,因此会出现错误。

一个try块(好吧,catch)告诉编译器"what's in here may result in an exception"。所以编译器假定,即使其中有 return 语句,try 可能不会 成功 return.

鉴于该假设,存在到达 catchfinally 的逻辑路径。由于这些 return 都不是,因此相同的逻辑路径将完全结束整个 try/catch/finally 并导致到达它之后的代码。

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

这是JLS 14.21的相关部分:

A try statement can complete normally iff both of the following are true:

  • The try block can complete normally or any catch block can complete normally.

  • If the try statement has a finally block, then the finally block can complete normally.

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

try语句可达,能正常完成,故其后语句可达。

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

你不需要考虑 try 块中的 return 语句,而是考虑 try 块本身。它看到 try 块并要求 catch 在那里(可选地它可以有一个 finally 块)。如果删除 catch 语句,则 try 块在发生错误时不知道该怎么做,因此将无法访问它下面的任何内容(因此出现无法访问的代码错误)

编译器认为"Well, what happens to this code if the try block does output an error - well the code below it won't execute cause I have not been told how to recover from that error"

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