Try-finally clauses defined and demonstrated

Through code samples, tables, and a Java virtual machine simulation, this article examines the bytecodes of the Java virtual machine that deal with finally clauses

1 2 Page 2
Page 2 of 2
   0 iconst_0             // Push constant 0
   1 istore_0             // Pop into local var 0: int i = 0;
                          // Both try blocks start here (see exception table, below).
   2 iconst_1             // Push constant 1
   3 istore_0             // Pop into local var 0: i = 1;
   4 jsr 16               // Jump to mini-subroutine at offset 16 (the first finally clause) 
   7 goto 22              // Jump to offset 22 (to just below first finally clause)
                          // Catch clause for the first finally clause:
  10 astore_3             // Pop the reference to thrown exception, store in local variable 3
  11 jsr 16               // Jump to mini-subroutine at offset 16 (the first finally clause)
  14 aload_3              // Push the reference (to thrown exception) from local variable 3
  15 athrow               // Rethrow the same exception
                          // The first finally clause:
  16 astore 4             // Store the return address in local variable 4
  18 iconst_2             // Push constant 2
  19 istore_0             // Pop into local var 0: i = 2;
  20 ret 4                // Jump to return address stored in local variable 4
                          // Bytecodes for the code just after the first finally clause:
  22 iconst_3             // Push constant 3
  23 istore_0             // Pop into local var 0: int i = 3;
                          // Bytecodes for the return statment:
  24 iload_0              // Push the int from local variable 0 (i, which is 3)
  25 istore_3             // Pop and store the int into local variable 3 (the return value, i)
  26 jsr 37               // Jump to mini-subroutine at offset 37 (the second finally clause)
  29 iload_3              // Push the int from local variable 3 (the return value)
  30 ireturn              // Return the int on the top of the stack
                          // Catch clause for the second finally clause:
  31 astore_1             // Pop the reference to thrown exception, store in local variable 1
  32 jsr 37               // Jump to mini-subroutine at offset 37 (the second finally clause)
  35 aload_1              // Push the reference (to thrown exception) from local variable 1
  36 athrow               // Rethrow the same exception
                          // The second finally clause:
  37 astore_2             // Store the return address in local variable 2
  38 iload_0              // Push the int from local variable 0 (i)
  39 iconst_3             // Push constant 3
  40 if_icmpne 46         // If the top two ints on the stack are unequal, jump to offset 46: if (i == 3) {
  43 goto 2               // Jump to offset 2 (the top of the while block): continue;
  46 ret 2                // Jump to return address stored in local variable 2
Exception table:
   from   to  target type
     2     4    10   any
     2    31    31   any

The hopAround() method returns from the first finally clause by executing past the closing curly brace, but returns from the second finally clause by executing a continue statement. The first finally clause, therefore, exits via its ret instruction. But because the second finally clause exits via a continue, its ret instruction is never executed. The continue statement causes the JVM to jump to the top of the while loop again. This results in an endless loop, even though it is a return statement that originally causes the second finally clause to be executed in the first place. The continue statement in the finally clause supersedes the return statement, so the method never returns.

Note that the bytecodes that implement the return statement store a copy of the return value into local variable 3 before jumping to the miniature subroutine that represents the second finally clause. Then, after the miniature subroutine returns (in this case it never does, because the continue is always executed), the return value is retrieved from local variable 3 and returned. This highlights the way the JVM returns values when finally clauses are also executed. Rather than returning the value of i after the finally clause is executed, the JVM will return the value that i had just before the finally clause was executed. This means that even if the finally clause changes the value of i, the method will still return the value that i had when the return statement was first reached, before the finally clause was invoked. If you wanted the finally clause to be able to change the return value of the method, you would have to put an actual return statement with the new return value into the finally clause itself.

To drive the simulation, just press the Step button. Each press of the Step button will cause the Java virtual machine to execute one bytecode instruction. To start the simulation over, press the Reset button. To cause the Java virtual machine to repeatedly execute bytecodes with no further coaxing on your part, press the Run button. The Java virtual machine will then execute the bytecodes until the Stop button is pressed. The text area at the bottom of the applet describes the next instruction to be executed. Happy clicking.

Bill Venners has been writing software professionally for 12 years. Based in Silicon Valley, he provides software consulting and training services under the name Artima Software Company. Over the years he has developed software for the consumer electronics, education, semiconductor, and life insurance industries. He has programmed in many languages on many platforms: assembly language on various microprocessors, C on Unix, C++ on Windows, Java on the Web. He is author of the book: Inside the Java Virtual Machine, published by McGraw-Hill.

Learn more about this topic

  • Previous Under The Hood articles
  • The lean, mean virtual machine -- Gives an introduction to the Java virtual machine. Look here to see how the garbage collected heap fits in with the other parts of the Java virtual machine.
  • The Java class file lifestyle -- Gives an overview to the Java class file, the file format into which all Java programs are compiled.
  • Java's garbage-collected heap -- Gives an overview of garbage collection in general and the garbage-collected heap of the Java virtual machine in particular.
  • Bytecode basics -- Introduces the bytecodes of the Java virtual machine, and discusses primitive types, conversion operations, and stack operations in particular.
  • Floating Point Arithmetic -- Describes the Java virtual machine's floating-point support and the bytecodes that perform floating-point operations.
  • Logic and Arithmetic -- Describes the Java virtual machine's support for logical and integer arithmetic, and the related bytecodes.
  • Objects and Arrays -- Describes how the Java virtual machine deals with objects and arrays, and discusses the relevant bytecodes.
  • Exceptions -- Describes how the Java virtual machine deals with exceptions, and discusses the relevant bytecodes.

1 2 Page 2
Page 2 of 2