Java has this great facility when dealing with exceptions called "finally". When you have a finally block, any code within it will execute regardless of whether an exception has been thrown or not. It's a good place to put code that must absolutely positively be run like closing files, database connections and any other similar resources. C# also has it and I believe it's also been standardized in C++, but not sure. Anyway, ever wonder how it is actually implemented?
I wrote a really simple method that just has a try, catch, finally block and examined the bytecode generated using this really cool Eclipse plug-in.
Here's the java code...
public void testFinally()
{
try
{
System.out.println( "try" );
}
catch ( Exception ex )
{
System.out.println( "catch" );
}
finally
{
System.out.println( "finally" );
}
}
and here's the bytecode...
// testFinally()V
L0 (7)
GETSTATIC java/lang/System.out: Ljava/io/PrintStream;
LDC "try"
INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V
GOTO L1
L2 (9)
ASTORE 1
L3 (11)
GETSTATIC java/lang/System.out: Ljava/io/PrintStream;
LDC "catch"
INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V
L4
GOTO L1
L5 (14)
ASTORE 3
JSR L6
ALOAD 3
ATHROW
L6
ASTORE 2
L7 (15)
GETSTATIC java/lang/System.out: Ljava/io/PrintStream;
LDC "finally"
INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V
L8 (16)
RET 2
L1 (14)
JSR L6
L9 (17)
RETURN
L10
LOCALVARIABLE this Ltest; L0 L10 0
LOCALVARIABLE ex Ljava/lang/Exception; L3 L4 1
MAXSTACK = 2
MAXLOCALS = 4
I don't understand bytecode. I would be interested in knowing more about it. But anyway, you don't need to be a bytecode specialist to understand how "finally" is always executed regardless of exception or not...
This is the "try" part
L0 (7)
GETSTATIC java/lang/System.out: Ljava/io/PrintStream;
LDC "try"
INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V
GOTO L1
and this is the "catch" part
L3 (11)
GETSTATIC java/lang/System.out: Ljava/io/PrintStream;
LDC "catch"
INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V
L4
GOTO L1
Notice any similarities? What is at "L1"?
L1 (14)
JSR L6
JSR is a jump instruction. So all this does is just to location L6. As you would suspect, it is the finally block...
L6
ASTORE 2
L7 (15)
GETSTATIC java/lang/System.out: Ljava/io/PrintStream;
LDC "finally"
INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V
Voila. Mystery solved!
I have to say that the bytecode is NOT the most diffcult thing in the world to interpret. A lot of it is pretty self-explanatory. I realize this is a real toy example and it gets more complicated, but it looks like something one can pick up. It's the same situation with IL code in the .NET world. I think maybe IL is a bit easier to read.
Maybe not the most important thing, but something that's interesting and nice to know.
No comments:
Post a Comment