前言
之前写了一篇 关于 try-catch-finally 执行顺序 的文章,但是写的有些繁琐了,这里重新写一下。
题目
1 | class Test { |
我第一次看到这个题,得出了几个问题:
- 如果在 try 语句块里有 return 语句,那么 finally 还会执行吗?
- 如果执行那应该是怎样的执行过程呢?
首先这道题的运行结果是 2,可能跟你想的不一样吧,别急,下面我会慢慢解释的。
在学习 Java 基础的时候,老师就讲过,try-catch-finally 中的 finally 语句块一定会被执行,那么我们来 debug 一下:
初始状态:
此时运行到了 return ++x;
但还没执行该语句,目前 x 的值为 1.
这时发现跳到了 finally 语句块中,且 return ++x
的 ++
操作已经执行,但没有进行 reutrn
,目前 x 的值为 2:
执行完 finally 语句块中的 ++x
操作后,又回到了 return 中,此时 x 的值为 3:
但根据最后的运行结果,我们发现其实真正 reutrn 的是 2,那么如何解释这一点呢?
其实在 官方的 JVM 规范 中对这一部分有说明:
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,那么代码的行为如下:
- 如果有返回值,就把返回值保存到局部变量中
- 执行 jsr 指令跳到 finally 语句里执行
- 执行完 finally 语句后,返回之前保存在局部变量表里的值
看完这个应该就能理解为什么返回的是 2 了,
但要注意的是:
- 如果在 finally 语句块中也使用了 return 语句,那么会忽略 try 中的 return 语句,而执行 finally 中的 return。
- 如果 try 中 return 的是引用数据类型,那么 finally 中的操作可能会影响最终的 return 值,因为对于引用数据类型,暂存到局部变量里的是它的地址值。