无法访问的代码工作正常 - 如何?

Jok*_*ker 57 java try-catch

从我的理解下面我写了不应该编译的语句代码"我不可达"是后return.

但是,编译绝对正常.

同样来自JLS:无法访问的语句,它不应该编译.

来自规范14.21无法到达的声明:

如果满足以下两个条件,则try语句可以正常完成:

  • try块可以正常完成,或者任何catch块都可以正常完成.

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

这里的try块无法正常完成,但catch块可以和finally块一样,所以我在这里很困惑

    public class Test1 {
     public static void main(String[] args) {
        try {
            return;

        } catch (Exception e) {
            System.out.println("catch");

        } finally {
            System.out.println("finally");
        }
        System.out.println("I am unreachable??!!!");
    }
}
Run Code Online (Sandbox Code Playgroud)

有人能帮我理解这种行为吗?

Era*_*ran 71

我相信这些是JLS 14.21的相关引用:

  • 如果可以访问,则不是交换机块的空块可以正常完成.

    非空交换块的非空块可以正常完成,如果其中的最后一个语句可以正常完成.

    如果块可以访问,则非空块中不是交换块的第一个语句是可到达的.

    如果S之前的语句可以正常完成,则非空交换块中的每个其他语句S都是可到达的.

所以你的

System.out.println("I am unreachable??!!!");
Run Code Online (Sandbox Code Playgroud)

语句是可达的iff(这意味着"当且仅当")try语句可以正常完成,这导致下一个引用:

  • 如果满足以下两个条件,则 try语句可以正常完成:

    • try块可以正常完成,或者任何catch块都可以正常完成.

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

由于您的catch块可以正常完成并且您有一个finally可以正常完成的块,因此该try语句可以正常完成.因此System.out.println("I am unreachable??!!!");,无论块return;内的语句如何,其后面的语句都被认为是可达的try.

请注意,or

try块可以正常完成,或者任何catch块都可以正常完成.

这要求try至少一个catch块正常完成.它不需要try块和catch块来正常完成.

最后,这种行为背后的逻辑:

编译器不应该分析try块是否可以抛出Exception.原因是Exception类层次结构包括已检查和未经检查的异常,并且未在throws子句中声明未经检查的异常(如果您替换Exception为某些已检查的异常,例如IOException,编译器会抱怨您的try块从不抛出该异常,这会使该catch块不可达).

因此,由于您有一个catch (Exception e)可以正常完成的块,编译器会假定此catch块可以访问,因此整个try语句可以正常完成,即使该try块无法正常完成.

finally块(如果存在)也必须能够正常完成,因为finally块也被执行,因此如果它无法正常完成,则整个try语句无法正常完成.

  • 我觉得chrylis到了那里,但他被打断了. (44认同)
  • @chrylis你会在"InterruptedException"中添加什么? (13认同)
  • 我要添加一件事--`InterruptedException`. (7认同)
  • 回到实现`Thread.stop(Throwable)`时(除了在调用者处抛出异常),即使是`return`语句也可能因异常而失败. (3认同)
  • @chrylis在Java中,术语*中断*用于通过`Thread.interrupt()`来发送信号,它只用"InterruptedException"结束阻塞操作(如`wait()`)或在显式查询时被检测到,即通过`Thread.interrupted()`.相反,通过`Thread.stop(...)`停止可能会强制导致任意代码位置的异常(包括那些试图处理这种异常的异常),这就是为什么它现在被弃用了很长时间甚至不支持最近的JVM用于其他throwables比`ThreadDeath`,它不是`Exception`的子类. (3认同)
  • @chrylis不是,所有这一切都设置了*旗*,仅此而已.该旗帜如何被"消费"是一个不同的故事 (2认同)

Ama*_*bra 15

你有回报的尝试.

如果有异常并直接捕获该怎么办?因此,它在编译器方面并不可达,并且正在成功编译.

如果您也将获得回收,则编译将失败

另外,根据JLS 14.21:

如果在break目标中没有try块语句包含break语句,或者try语句的try块包含break语句,并且那些try语句的所有finally子句都可以完成,则可达到的break语句将退出语句一般.

当你在try和catch中返回时,请参阅下面的输出:

jshell>  public class Test1 {
   ...>     public static void main(String[] args) {
   ...>         try {
   ...>             return;
   ...>
   ...>         } catch (Exception e) {
   ...>             return;
   ...>
   ...>         }
   ...>
   ...>         System.out.println("I am unreachable??!!!");
   ...>     }
   ...> }
|  Error:
|  unreachable statement
|          System.out.println("I am unreachable??!!!");
|          ^------------------------------------------^
Run Code Online (Sandbox Code Playgroud)

如果在finally语句中返回并且编​​译失败,则会出现类似情况.

如果出现以下情况,将认为声明帖子尝试可达:

1) Try has a return statement with catch and finally not having return statement
2) Try does not have a return statement with catch having or not having return statement and finally not having return statement
3) Try, catch and finally not having return statement
Run Code Online (Sandbox Code Playgroud)


Yas*_*ava 10

试图给出问题的更简化原因,代码是可达的,以防try块中发生异常.在这种情况下,控制进一步进入catch块,然后进入finally块.在finally块之后,将执行特定语句.

try {
            return;                                 //line 1

        } catch (Exception e) {
            System.out.println("catch");            //line 2

        } finally {
            System.out.println("finally");          //line 3
        }
        System.out.println("I am unreachable??!!"); //line 4
Run Code Online (Sandbox Code Playgroud)

这意味着,有2个案例,因此有2个流程:

  1. 第1行 - >第3行 - >返回(如果没有异常)
  2. 第1行(发生异常) - >第2行 - >第3行 - >第4行(如果尝试获取异常)

只有当我们不保留任何控制权的可能性时,该线路才会无法到达.有两种方法:

  1. 从catch块返回
  2. 从finally块返回.

在这两种情况下,控件永远不会流向该行.

try {
            return;                                 //line 1

        } catch (Exception e) {
            System.out.println("catch");            //line 2
            return;                                 //return control
        } finally {
            System.out.println("finally");          //line 3
            return;                                 //or return from here
        }
        System.out.println("I am unreachable??!!"); //line 4    
Run Code Online (Sandbox Code Playgroud)

我希望现在能够清楚地了解问题的实际原因.

  • @YashiSrivastava因为`finally`块中的`return`会覆盖catch块中的任何返回,并且它也会吞下异常.请参阅[此问题](/sf/ask/3366191/)及其答案. (7认同)
  • 此外,它可以替换**'try`-block(或`catch`-block)中的`return`语句成功评估后返回的值** - 这可能会导致一些头痛:[见这个问题](/sf/ask/161697511/) (3认同)
  • @jwenting:也许是SESE纯粹主义者和货物崇拜者.但不是"一般".如果您知道要返回什么,那么返回是最合适的事情.(有很好的理由不在"finally"块中返回,但它们与SESE关联较少,而且更多的是使代码撒谎.) (3认同)