The definition of the return
statement in the current Java Language Specification (§14.17) features an innocuous-looking sentence:
It can be seen, then, that a return statement always completes abruptly.
Other statements that “always complete abruptly” include break
(§14.15), continue
(§14.16), and of course throw
(§14.18). So what? Well, Java also has try-finally
blocks (§14.20). As you would expect, exceptions thrown in a finally
clause override any previous exception thrown in the associated try
block. But this override is defined in terms of “abrupt completion” – and therefore applies to all jump statements!
Generally, the abrupt completion of a finally
clause hides any previous abrupt completion of the associated try
block. Let’s see what this means in practice.
Jump Hides Exception
Most importantly, simply returning from a finally
clause will swallow any previous exception. The following method will never propagate the exception it throws:
static void neverThrows() {
try {
throw new RuntimeException();
} finally {
return;
}
}
Dustin Marx has compiled some examples and links on this surprising behavior, on the occasion of a new warning message in NetBeans 7.4. You can also use the compiler option -Xlint:finally
to warn against “abrupt completion” in finally
clauses.
Jump Hides Return
You don’t even need to throw exceptions. Ordinary jump statements will hide each other when finally
clauses are involved. Consider the following method:
static int neverPlusOne() {
for(;;) {
try {
return +1;
} finally {
break;
}
}
return -1;
}
This method always returns -1, not +1, because the break
in the finally
clause overrides the early return +1
in the try
block. The code snippet is from the Java Hall of Shame which also provides a continue
example. As the end of JSL §14.18 quaintly states,
Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement.
The same caveats apply to finally
blocks in JavaScript, by the way. C# avoids the whole mess by simply forbidding jumps out of finally
blocks. I added a note on Java’s surprisingly different behavior to Java for C# Programmers.