RuntimeException is an unchecked exception. The compiler doesn't go inside method bodies to see what exceptions are thrown there, it only checks for (as the name implies) checked exceptions that are declared in the throws-clause of a method header.
This is an example of where the compiler, per the Java Language Specification doesn't do as deep an analysis of code as we might when we are looking at it, or a good static analysis tool likely would.
The JLS is incredibly specific on which things must be reported as compiler errors to be a compliant javac compiler. I knew that for a very long time, and thought it Was Good.
What I didn't realize at first, is that in order to have similar behavior for the same code everywhere, they are also prohibited from making quite a number of things as compiler errors that it would seem reasonable that they could. If some did, you would wind up with code that compiled using one javac and would generate a compile failure using another one, perhaps even the same release [e.g. 8, 11, 15].
So if you looked at the JLS in this regard (for Java SE 16 this is JLS 14.22) you would see very detailed rules for how the compiler must determine that code is Unreachable.
I don't really recommend reading that unless you feel terminally curious.
So the compiler isn't required to do an exhaustive heuristic analysis for Unreachable Code, which might necessitate looking at code that it can't even see, because it could involve Java code that is just on the CLASSPATH etc. and not available as source.
It has moderately simple, moderately complex rules that every single javac must implement in the same way for finding some "obvious" instances of Unreachable Code to help prevent developers from making stupid mistakes, or at least, from checking them in.
In this specific example, because throws means might perhaps throw, if an exception is a checked type, it will ensure that code calling it either handles (catch) or again throws it.
This required behavior is described in Section 11.2 of the JLS. It seemed reasonable to infer that it would see in your case that the code is unreachable, and many code analyzers (and good developers) would see it, but the compiler is neither required nor allowed to show this case as an error.
The answer seems a little Unsatisfying, because what you want to know is which things will result in Compiler Errors and which won't, and nobody expects you to memorize the JLS.
I apologize, I might have put you on the wrong track with my comment about checked exceptions.
Code is unreachable when (among other reasons) a line before it will ALWAYS throw an exception. For a throw-statement, this is obvious. For a method call, it is not. The compiler would have to go into the method and analyse its body. Java does not do this, because it is prohibitively expensive, and not even possible in all cases.
In short, regardless of whether a method will ALWAYS throw an exception, the compiler won't check that it does, and so a method call can never cause code to become unreachable as far as the compiler is concerned.
Sumi Lee wrote:Thank you Stephan and Jesse both for helping out. I was not aware of how compilers work in such detail.
highly appreciate your help and clarification!
You are welcome. And it is not all compilers! In the world of C/C++ there is a very great latitude in what the compiler may or may not decide is an error, which is lots of fun when your code starts getting built in 20 different places. At least with Java there is One Real Answer as to whether or not something will compile, tho in some cases we may not be sure of it until we read the JLS or try to compile something. Once we know the answer it is unlikely to change, and THAT is welcome too!
RTFJD (the JavaDocs are your friends!) If you haven't read them in a long time, then RRTFJD (they might have changed!)
Try 100 things. 2 will work out, but you will never know in advance which 2. This tiny ad might be one: