关于 try 和 finally 中的 return

关于 try 和 finally 中的 return

首先咱们来看一段代码:html

public class Test {

    public static int inc() {
        int x = 1;

        try {
            return ++x; // 1*
        } catch (Exception e) {
            
        } finally {
            x++;
        }

        return x;
    }

    public static void main(String[] args) {
        System.out.println(inc());
    }
}

它的输出结果是多少呢?java

2

咱们走一下这个过程,x 的初始值是 1,而后进入到了 try 语句块中,在 1* 处,++x,x 会先自增,如今 x = 2,以后 return,return 是用来跳出当前方法,而 finally 是不管 try 语句发生了什么,都会执行的一个语句块,那么 try 中 return 和 finally 执行的顺序究竟是谁先谁后呢?程序员

咱们来看 Oracle 文档中对 finally Block 的描述 The finally Block (The Java™ Tutorials > Essential Classes > Exceptions)express

The finally Block

The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs. But finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.oracle

Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.

从这段解释中咱们能够知道,当 try 语句块退出时,finally 语句块老是会执行,这保证了当有异常发生时,finally 语句块会被执行,不过 finally 语句块的做用不只于此,它帮助程序员避免在执行 return or continue or break 时绕过清理代码,因此即便没有异常须要捕获,将清理代码放到 finally 语句块中也是一个好的选择。app

须要注意的是,只有一种状况:若是在执行 try or catch 语句时 JVM 退出了,好比咱们调用 System.exit,那么 finally 才不会被执行。jvm

在 Java 语言规范 Chapter 14. Blocks and Statements 中也提到:ide

The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any try statements (§14.20) within the method or constructor whose try blocks or catch clauses contain the return statement, then any finally clauses of those try statements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement.

若是在 try or catch 语句块中包含 return 语句,那么 finally 语句会在其 return 以前执行。lua

根据以上描述,咱们知道了 finally 语句块会在 try or catch 语句块执行前执行,那么当 x 自增后,会继续执行 finally 语句块中的内容,即 x++,那么此时 x = 3,但是这段程序的返回结果是 2 ,这又是为何呢?code

咱们来看 JVM 规范中的描述 Chapter 4. The class File Format

Control can be transferred to the finally clause (the finally subroutine can be invoked) in several different ways. If the try clause completes normally, the finally subroutine is invoked via a jsr instruction before evaluating the next expression. A break or continue inside the try clause that transfers control outside the try clause executes a jsr to the code for the finally clause first. If the try clause executes a return, the compiled code does the following:

  1. Saves the return value (if any) in a local variable.
  2. Executes a jsr to the code for the finally clause.
  3. Upon return from the finally clause, returns the value saved in the local variable.

也就是说,若是 try 语句中包含 return,那么编译后的代码会执行如下操做:

  1. 将 return 的值存到一个局部变量中
  2. 执行 jsr 指令到 finally 语句块中的代码
  3. 从 finally 语句返回时,返回在局部变量中保存的值

终于,谜团揭开了!原来在 finally 语句中执行完毕后,它会返回存在局部变量中的在 try 语句块中 return 的值,所以它返回的是 1* 处的 x,也就是返回的 2。

而且还须要注意的是,finally 中的 return 会覆盖 try 中的 return。

参考资料:

http://www.cnblogs.com/averey...
https://docs.oracle.com/javase

相关文章
相关标签/搜索