This question is aimed at how the JVM is able to guarantee the execution of a finally block (provided the JVM doesn\'t crash and the thread is not interrupted o
I believe this blog clearly describes the internal:
If a method has defined a try-catch or a try-finally exception handler then an Exception Table will be created. This contains information for each exception handler or finally block including the range over which the handler applies, what type of exception is being handled and where the handler code is.
When an exception is thrown the JVM looks for a matching handler in the current method, if none is found the method ends abruptly popping the current stack frame and the exception is re-thrown in the calling method (the new current frame). If no exception handler is found before all frames have been popped then the thread is terminated. This can also cause the JVM itself to terminate if the exception is thrown in the last non-daemon thread, for example if the thread is the main thread.
Finally exception handlers match all types of exceptions and so always execute whenever an exception is thrown. In the case when no exception is thrown a finally block is still executed at the end of a method, this is achieved by jumping to the finally handler code immediately before the return statement is executed.
Compile this little program (I realized I should have used your example, but it makes no difference)
public static void main(String[] args) {
try {
Float s = Float.parseFloat("0.0327f");
} finally {
System.out.println("hello");
}
}
I used
>java -version
java version "1.8.0-ea" // should be same for 7
Java(TM) SE Runtime Environment (build 1.8.0-ea-b118)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b60, mixed mode)
And then execute
javac -v -c <fully qualified class name>
to get the bytecode. You will see something like
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: ldc #2 // String 0.0327f
2: invokestatic #3 // Method java/lang/Float.parseFloat:(Ljava/lang/String;)F
5: invokestatic #4 // Method java/lang/Float.valueOf:(F)Ljava/lang/Float;
8: astore_1
9: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
12: ldc #6 // String hello
14: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
17: goto 31
20: astore_2
21: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
24: ldc #6 // String hello
26: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
29: aload_2
30: athrow
31: return
Exception table:
from to target type
0 9 20 any
20 21 20 any
LineNumberTable:
line 10: 0
line 12: 9
line 13: 17
line 12: 20
line 14: 31
StackMapTable: number_of_entries = 2
frame_type = 84 /* same_locals_1_stack_item */
stack = [ class java/lang/Throwable ]
frame_type = 10 /* same */
You'll notice the code inside the finally
appears twice, once before the goto
and once after. You'll also notice the Exception table
which specifies which statement to go to if an exception occurs at some line.
So if any exception happens between statement 0-9, go to line 20 and execute the everything inside the finally
, after the goto
. If no exception occurs, execute the finally
and then execute the goto
skipping the finally
after the goto
.
In all cases you will have executed the code inside the finally
block.
Other Exception not being explicitly handled
With a finally
block, an Exception table
entry will be created that will handle any type of Throwable
.
Here's a listing of the bytecode instructions.