Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unreachable code compiling without error - How?

Tags:

java

try-catch

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

However, When I ran this code 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?

like image 751
Sachin Sachdeva Avatar asked Jul 25 '18 05:07

Sachin Sachdeva


People also ask

How do you solve an unreachable statement?

If you keep any statements after the return statement those statements are unreachable statements by the controller. By using return statement we are telling control should go back to its caller explicitly .

Is unreachable code a compile time error?

If any code can not be executable in any of the possible flows, then it is called unreachable code. Unreachable code in java is a compile time error.

Why does it say my code is unreachable?

In computer programming, unreachable code is part of the source code of a program which can never be executed because there exists no control flow path to the code from the rest of the program.


2 Answers

I believe these are the relevant quotes from JLS 14.21:

  • An empty block that is not a switch block can complete normally iff it is reachable.

    A non-empty block that is not a switch block can complete normally iff the last statement in it can complete normally.

    The first statement in a non-empty block that is not a switch block is reachable iff the block is reachable.

    Every other statement S in a non-empty block that is not a switch block is reachable iff the statement preceding S can complete normally.

So your

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

statement is reachable iff (that means "if and only if") the try statement can complete normally, which leads to the next quote:

  • 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.

Since your catch block can complete normally and you have a finally block that can complete normally, the try statement can complete normally. Hence the System.out.println("I am unreachable??!!!"); statement following it is deemed reachable, regardless of the return; statement inside the try block.

Note the or in

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

This requires either the try block or at least one of the catch blocks to complete normally. It doesn't require both the try block and catch block to complete normally.

Finally, the logic behind this behavior:

The compiler is not supposed to analyze whether a try block can or cannot throw an Exception. The reason is that the Exception class hierarchy includes both checked and unchecked exceptions, and unchecked exceptions are not declared in throws clauses (if you replaced Exception with some checked exception, such as IOException, the compiler would complain that your try block never throws that exception, which would make the catch block unreachable).

Therefore, since you have a catch (Exception e) block which can complete normally, the compiler assumes that this catch block it reachable, and therefore the entire try statement can complete normally, even though the try block cannot complete normally.

The finally block, if present, must also be able to complete normally, since the finally block is also executed, so if it couldn't complete normally, the entire try statement couldn't complete normally.

like image 94
Eran Avatar answered Sep 22 '22 22:09

Eran


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 
like image 26
Aman Chhabra Avatar answered Sep 19 '22 22:09

Aman Chhabra