Java's compiler, at least the one from Oracle that I use, refuses to recognize System.exit() as a procedure termination. For example, the following code gives a compilation error:
public static int readInteger( ArrayList<String> listLines, int iLineNumber0 ){
try {
int value = Integer.parseInt( listLines.get( 0 ) );
return value;
} catch( Throwable t ) {
System.err.println( "error reading line: " + iLineNumber0 + ": " + t );
System.exit( -1 );
}
}
The error is: "Missing return statement." Therefore, to make this work I have to add in a return statement like this (compiles successfully):
public static int readInteger( ArrayList<String> listLines, int iLineNumber0 ){
try {
int value = Integer.parseInt( listLines.get( 0 ) );
return value;
} catch( Throwable t ) {
System.err.println( "error reading line: " + iLineNumber0 + ": " + t );
System.exit( -1 );
}
return 0; // unreachable code
}
Ironically, the final return statement that is needed is unreachable code, although the compiler does not realize this either.
Java's compiler, at least the one from Oracle that I use, refuses to recognize System.exit() as a procedure termination.
Yes, it would. As far as the compiler is concerned, it's just a void
method. There's no way of indicating "this method never returns normally" in a method signature, and no such concept in the language. For example:
public void alwaysThrow()
{
throw new RuntimeException();
}
...
alwaysThrow();
System.out.println("This line is never reached");
The last line in the above snippet is still reachable as far as the compiler is concerned, even though we know it will never execute. Likewise your extra return statement is technically reachable, but practically unreachable.
Basically this could be deemed a flaw in the language, although it's one which affects most languages as far as I'm aware. While it would be nice to be able to represent methods like this, it's rarely a real issue in real life.
If you find yourself bothered by it, you could write a helper method:
public RuntimeException systemExit(int exitValue)
{
System.exit(exitValue);
return new RuntimeException("Shouldn't get here");
}
Then call it as:
throw systemExit();
That will ensure that the end of the statement is unreachable as far as the compiler is concerned, so you could have:
catch (Throwable t) {
System.err.println("error reading line: " + iLineNumber0 + ": " + t);
throw systemExit(-1);
}
... and your compiler error would go away.
Note that there are other similar situations where reachability isn't everything we might want. For example:
int foo() {
int x = someValue();
if (x > 10) {
return 1;
}
if (x <= 10) {
return 20;
}
// Is this reachable or not?
}
We know that any value of x
will either be greater than 10 or less-than-or-equal-to 10, so the final line is practically unreachable but the rules of the language don't express that... so even a smart compiler can't actually treat the above code as valid without violating the language specification.
See more on this question at Stackoverflow