The finally block gets always executed as last. So the return in the finally block OVERWRITES the other returns in the try/catch blocks.
It's a very bad practice to return or throw an exception from the finally block for this reason.
Nothing to do with stacks: it's a matter of the fact that the finally block gets always executed as last block, so what is returned or thrown in the finally block erases and overwrites any previous exit value (returned object or exception thrown).
Try this:
try {
throw new NullPointerException();
}
finally {
return 0;
}
The return in the finally block will overwrite (swallow) the NullPointerException...