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