Unreachable code working fine - How?

时间:2018-07-25 05:16:44

标签: java try-catch

From my understanding following code that I have written should not compile as the statement "I am unreachable" is after the return.

However, it is compiling absolutely fine.

Also from the JLS:Unreachable Statements it should not compile.

from the spec, at 14.21 Unreachable Statements:

A try statement can complete normally if 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.

Here the try block can't complete normally but the catch block can as well as the finally block, so I am confused here

    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??!!!");
    }
}

Can someone help me understand this behavior?

4 个答案:

答案 0 :(得分:71)

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

  
      
  • 一个不是交换块的空块只要可以到达就可以正常完成。

         

    非空块(不是交换块)可以正常完成,前提是其中的最后一条语句可以正常完成。

         

    非空块(不是交换块)中的第一条语句只要该块可以到达,就可以到达。

         

    非空块中不是交换块的其他所有语句S都可以访问,前提是S之前的语句可以正常完成

  •   

所以你

System.out.println("I am unreachable??!!!");

仅当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替换为某些已检查的异常,例如{{ 1}},编译器会抱怨您的try块永远不会抛出该异常,这会使IOException块无法访问)。

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

finally块(如果存在)还必须能够正常完成,因为try块也已执行,因此,如果无法正常完成,则整个try语句将无法正常完成。 / p>

答案 1 :(得分:15)

You have return in try.

What if there is an exception and it directly goes to catch. Hence it is not unreachable in terms of compiler and is compiling successfully.

Compilation will fail if you will have return in catch as well

Also, as per JLS 14.21:

A reachable break statement exits a statement if, within the break target, either there are no try statements whose try blocks contain the break statement, or there are try statements whose try blocks contain the break statement and all finally clauses of those try statements can complete normally.

See output below when you have return in both try and 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??!!!");
|          ^------------------------------------------^

Similar will be the case when you have return in your finally statement and compilation will fail.

A statement post try will be considered as reachable if :

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

答案 2 :(得分: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

这意味着有2种情况,因此有2种流:

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

仅当我们不保留任何控制权的情况下,该线路才会变得不可达。有两种方法:

  1. 从捕获块返回
  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    

我希望现在能清楚地说明问题的实际原因。

答案 3 :(得分:4)

当您查看Java程序中的“无法到达的语句”时,最重要的是该语言中所定义的内容,而不是聪明的编译器可以找到的内容。

根据Java语言,最后一个println不是不可访问的语句。即使通过查看代码,对于聪明的人来说,也很容易弄清楚它永远不会被执行。

一种编程语言需要依赖固定的规则,这些规则对于编译器来说很容易准确遵循。编译器不能依靠聪明,因为不同的编译器将具有不同程度的聪明,因此,如果它们不遵循简单的固定规则,则某些编译器会发现该语句不可访问,而有些则不会。