资讯专栏INFORMATION COLUMN

关于 try 和 finally 中的 return

jeyhan / 3104人阅读

摘要:在语言规范中也提到如果在语句块中包含语句,那么语句会在其之前执行。并且还需要注意的是,中的会覆盖中的。

关于 try 和 finally 中的 return

首先我们来看一段代码:

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());
    }
}

它的输出结果是多少呢?

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)

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.

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 语句块中也是一个好的选择。

需要注意的是,只有一种情况:如果在执行 try or catch 语句时 JVM 退出了,比如我们调用 System.exit,那么 finally 才不会被执行。

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

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 之前执行。

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

我们来看 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:

Saves the return value (if any) in a local variable.

Executes a jsr to the code for the finally clause.

Upon return from the finally clause, returns the value saved in the local variable.

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

将 return 的值存到一个局部变量中

执行 jsr 指令到 finally 语句块中的代码

从 finally 语句返回时,返回在局部变量中保存的值

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

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

参考资料:

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69373.html

相关文章

  • Will it finally: 关于 try/catch 的一些细节

    摘要:随着的出现,我最近发现自己在我的代码中使用了更多。但老实说,我终于用做了一点练习。当我去实际使用它时,我有点不确定它的细节。事实上,这就是本文的灵感来源。 随着async /await的出现,我最近发现自己在我的代码中使用了更多try /catch /finally。但老实说,我终于用finally做了一点练习。当我去实际使用它时,我有点不确定它的细节。所以我把几个例子放在一起。 当你...

    asce1885 评论0 收藏0
  • Will it finally: 关于 try/catch 的一些细节

    摘要:随着的出现,我最近发现自己在我的代码中使用了更多。但老实说,我终于用做了一点练习。当我去实际使用它时,我有点不确定它的细节。事实上,这就是本文的灵感来源。 随着async /await的出现,我最近发现自己在我的代码中使用了更多try /catch /finally。但老实说,我终于用finally做了一点练习。当我去实际使用它时,我有点不确定它的细节。所以我把几个例子放在一起。 当你...

    zhangrxiang 评论0 收藏0
  • Will it finally: 关于 try/catch 的一些细节

    摘要:随着的出现,我最近发现自己在我的代码中使用了更多。但老实说,我终于用做了一点练习。当我去实际使用它时,我有点不确定它的细节。事实上,这就是本文的灵感来源。 随着async /await的出现,我最近发现自己在我的代码中使用了更多try /catch /finally。但老实说,我终于用finally做了一点练习。当我去实际使用它时,我有点不确定它的细节。所以我把几个例子放在一起。 当你...

    褰辩话 评论0 收藏0
  • try-catch-finally中的return

    摘要:基础系列的与方法类初始化顺序线程池如何弹性伸缩的几个要点的缓存什么场景下使用阻塞队列的使用及模式中的序本文主要简述中有的情况。参考关于中的执行顺序 Java基础系列 Java的hashcode与equals方法 Java类初始化顺序 ThreadPoolExecutor线程池如何弹性伸缩 HashMap的几个要点 Integer的缓存 什么场景下使用阻塞队列 volatile的使用及...

    fizz 评论0 收藏0

发表评论

0条评论

jeyhan

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<