The finally keyword in Java is usually used with the try catch block. Used to perform some resource release operations before the end of the method or when an exception occurs. Recently I have also seen some articles on the Internet discussing the order of the execution of try catch finally keywords, and it is given that the finally block is executed at the end of the method.
These views generally believe that:
1) The finally keyword is executed before returning to the previous method after the program return statement. The return value will be saved in a temporary area. After the final block is executed, the value of the temporary area will be returned.
2) If there is a return value in the finally block, it will replace the value stored in the temporary area of the previous try or catch block in the program.
But is the problem really like this? Let's think about it carefully. JVM explains and executes bytecode instructions at runtime. When it executes the return statement, he doesn't know if there is a finally block afterward? What if there is no finally block? Whether it is a bytecode instruction or a computer instruction should be clear. JVM is not that smart. The same instruction must be clear and will not contain two meanings. Therefore, no matter what the return statement is when running, the content of the stack will be popped up and returned to the calling method.
At the same time, we can see that the book "Deep into Java Virtual Machine" gives another explanation. When the java compiler compiles the finally clause, a jsr instruction will be generated. It causes the jvm to be called to a mini subroutine for execution, that is, at the finally block. At the same time, the return 0 statement in the program is compiled into the return variable in the stack to the local variable before calling the jsr instruction, and the jsr instruction is called, the finally block is executed, and the finally block returns. When the return value in the local variable is pushed into the stack, the ireturn instruction is executed, the return value pops up from the stack, and returns to the call method. Here, the return value is saved in the local variable before executing the jsr instruction, because an exception may occur during the execution of the finally block or there are also returns values. Only in this way can the consistency of the final program execution be ensured. Since "Deepening Java Virtual Machine" has been written for some time, the implementation and version of the jvm compiler used by the author is also different from the one discussed in this article. So after testing, there is a slight difference in the generation of bytecodes for different compiler implementations or versions of different compilers for the same program. If you are interested, you can take a look at the bytecode generated by the finally clause in this book.
The bytecode generation in this article is compiled and generated by Oracle's jdk8u-25 version of the compiler.
Let's take a look at an example below.
1.try catch finally example:
public class FinallyTest { public static void main(String[] args) { int r = test(); System.out.println(r); } public static int test() { try { System.out.println("try"); //return 1/0; return 0; } catch (Exception e) { System.out.println("exception"); return 100; } finally{ System.out.println("finally"); } }}Use the return 0 statement in the try block, and the running result of the program is:
try
Finally
0
Use the return 1/0 statement in the try block, and the result of the program running is:
Exception
Finally
100
In fact, through the running result, we can see that the finally block is executed after other statements before the return statement in the try or catch block. In other words, the writing order of the program does not match our execution order, because jvm interprets and executes bytecode, so we need to see how the java compiler compiles this code and see what the generated by the bytecode looks like.
2. Part of the bytecode generated by the program: (please refer to the java bytecode instruction)
public static int test(); descriptor: ()I flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=0 0: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #36 // String try 5: invokevirtual #38 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream; 11: ldc #41 // String finally 13: invokevirtual #38 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 16: iconst_0 17: ireturn 18: store_0 19: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream; 22: ldc #43 // String exception 24: invokevirtual #38 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 27: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream; 30: ldc #41 // String finally 32: invokevirtual #38 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 35: bipush 100 37: ireturn 38: store_1 39: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream; 42: ldc #41 // String finally 44: invokevirtual #38 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 47: aload_1 48: athrow Exception table: from to target type 0 8 18 Class java/lang/Exception 0 8 38 any 18 27 38 any
From the red part, we can see that lines 10 and 11 correspond to finally block statement instructions, 16 and 17 correspond to return 0 instructions, after other statements on try block, before return. 19 and 20 correspond to finally block instructions, 21 and 22 correspond to the instructions of return 100 statements. After catching other statements and before returning, we can see that everything happens behind these is that the java compiler has done all this for us. As for the exceptions that occur in the program, jvm will find the corresponding address location for handling exceptions from the exception table to execute.
Therefore we can conclude that the statements in finally blocks will be inserted by the java compiler before the try block and catch block return statement, and after the other statements. There are no subroutines to generate jsr calls here. That's why, whether it is executing the try block or executing the catch block, the finally block will be executed before the method returns.
The above comprehensive analysis of the execution timing of java finally blocks is all the content I share with you. I hope you can give you a reference and I hope you can support Wulin.com more.