本章节我们从字节码的角度来探究下return和finally到底哪个先执行。下面先来看一段简单地源码:public class ReturnFinallyDemo {

public static void main(String[] args) {

System.out.println(case1());

}

public static int case1() {

int x;

try {

x = 1;

return x;

} finally {

x = 3;

}

}

}# 输出1

上述代码的输出可以简单地得出结论:return在finally之前执行,我们来看下字节码层面上发生了什么事情。下面截取case1方法的部分字节码,并且对照源码,将每个指令的含义注释在后面:iconst_1 // 将常量1推入操作数栈顶

istore_0 // 弹出栈顶元素(1),保存到局部变量表slot[0],此时slot[0]=1。这两条指令对应源码:x = 1;

iload_0 // 将局部变量表slot[0]的值推入操作数栈顶,也就是说把上面x的值推入栈顶

istore_1 // 弹出栈顶元素(1),保存到局部变量表slot[1],此时slot[1]=1。其实,此时就已经把要return的值准备好了

iconst_3 // 将常量3推入操作数栈顶,这一条指令开始,其实是开始执行finally中的代码了

istore_0 // 弹出栈顶元素(3),保存到局部变量表slot[0],此时slot[0]=3。这两个指令对应源码:x = 3;这里要注意的是,虽然都是更新了x的值,但是finally中的x和try中x的赋值,保存在了不同的局部变量表中

iload_1 // 将局部变量表slot[1]的值推入操作数栈顶,此时栈顶元素的值为1,是第3行指令保存的值

ireturn // 将操作数栈顶的值返回给调用方

从字节码来看,似乎又是finally的代码先执行了,因为ireturn指令确实是在最后执行的,所以返回什么样的值不在于谁先执行,而在于ireturn指令返回的操作数栈顶的元素是何时保存的。在上述代码环境中,是try代码块中給x赋值的版本,也就是紧接着return语句后面的x所保存的版本。

下面再来看一个稍微复杂点的场景:public static int case2() {

int x;

try {

x = 1;

return ++x;

} finally {

x = 3;

}

}# 输出2

有了上面的分析,这个就很好理解了,我们还是来看下字节码:iconst_1 // 将常量1推入操作数栈顶

istore_0 // 弹出栈顶元素(1),保存到局部变量表slot[0],此时slot[0]=1。这两条指令对应源码:x = 1;

iinc          0, 1 // 对局部变量表slot[0]进行自增(+1)操作,此时slot[0]=2,对应源码:++x;所以,可以看出return后面的表达式先执行

iload_0 // 将局部变量表slot[0]的值推入操作数栈顶,也就是说把上面x的值(2)推入栈顶

istore_1 // 弹出栈顶元素(2),保存到局部变量表slot[1],此时slot[1]=2。其实,此时就已经把要return的值准备好了

iconst_3 // 将常量3推入操作数栈顶,这一条指令开始,其实是开始执行finally中的代码了

istore_0 // 弹出栈顶元素(3),保存到局部变量表slot[0],此时slot[0]=3。这两个指令对应源码:x = 3;这里要注意的是,虽然都是更新了x的值,但是finally中的x和try中x的赋值,保存在了不同的局部变量表中

iload_1 // 将局部变量表slot[1]的值推入操作数栈顶,此时栈顶元素的值为2,是第6行指令保存的值,也就是经过++x之后的值

ireturn // 将操作数栈顶的值返回给调用方

从上述代码可以看出,return后面的指令先执行,然后保存到局部变量表,接着执行finally中的语句,最后执行return指令本身。

总结一下,return指令是最后执行的,如果return后面有表达式,则执行完表达式之后就执行finally中的语句,最后再执行return指令。所以说finally和return到底哪个先执行:return指令后面如果有表达式或方法调用的话,先执行,然后执行finally,最后执行return指令。就像上面的程序演示的结果,不能光从x的赋值来看最终返回结果,从指令层面看,两次对x的赋值,保存在局部变量表的位置不一样。

最后,再来看一个平时不会这么去写的场景:public static int case3() {

int x;

try {

x = 1;

return ++x;

} finally {

x = 3;

return x;

}

}# 输出3

这是一个finally返回结果的示例,平时不建议这么写,我们同样从字节码的角度来分析下:iconst_1 // 将常量1推入操作数栈顶

istore_0 // 弹出栈顶元素(1),保存到局部变量表slot[0],此时slot[0]=1。这两条指令对应源码:x = 1;

iinc          0, 1 // 对局部变量表slot[0]进行自增(+1)操作,此时slot[0]=2,对应源码:++x;所以,可以看出return后面的表达式先执行

iload_0  // 将局部变量表slot[0]的值推入操作数栈顶,也就是说把上面x的值(2)推入栈顶

istore_1 // 弹出栈顶元素(2),保存到局部变量表slot[1],此时slot[1]=2。

iconst_3 // 将常量3推入操作数栈顶,这一条指令开始,其实是开始执行finally中的代码了

istore_0 // 弹出栈顶元素(3),保存到变量表slot[0],此时slot[0]=3。这两个指令对应源码:x = 3

iload_0  // 将局部变量表slot[0]的值(3)推入操作数栈,这是跟之前不一样的地方,ireturn返回的值选择的局部变量表不一样

ireturn

从字节码以及解释来看,直接忽略了try语句块中的return指令,这样的代码会让人产生疑惑,所以平时不建议这么写。本章节就到这里了。

java中return finally_Java中return和finally到底哪个先执行相关推荐

  1. java 异常 return_Java异常处理中同时有finally和return语句的执行问题

    在Java中当try.finally语句中包含return语句时,执行情况到底是怎样的,finally中的代码是否执行,大家众说纷纭,有的说会执行,有的说不会执行,到底哪种说法正确,现在通过下面的例子 ...

  2. java异常处理:finally中不要return

    java异常处理:finally中不要return 参考文章: (1)java异常处理:finally中不要return (2)https://www.cnblogs.com/Fskjb/archiv ...

  3. 你真的了解try{ return }finally{}中的return?

    你真的了解try{ return }finally{}中的return? 今天去逛论坛 时发现了一个很有趣的问题: 谁能给我我解释一下这段程序的结果为什么是:2.而不是:3 代码如下: class T ...

  4. JavaScript 中的return true 和return false

    2019独角兽企业重金招聘Python工程师标准>>> 1.对于return true 和 return false: return false表示返回一个false值,也就是说提交 ...

  5. Sql Server 中存储过程的output return的区别

    看http://zxianf.blog.163.com/blog/static/301207012009114104124969/中片关于Sql Server中存储过程output和return值的区 ...

  6. php 类中调用另类,PHP return语句另类用法不止是在函数中,return语句_PHP教程

    PHP return语句另类用法不止是在函数中,return语句 分享下PHP return语句的另一个作用,在bbPress的代码中看到的一个奇葩使用方法. 一直以为,return只能出现在函数中, ...

  7. vue中的data用return返回

    为什么在大型项目中data需要使用return返回数据呢? 答:不使用return包裹的数据会在项目的全局可见,会造成变量污染:使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件. ...

  8. JavaScript 中,break , continue , return 的区别

    break , continue , return 的区别 break :结束当前的循环体(如 for.while) continue :跳出本次循环,继续执行下次循环(如 for.while) re ...

  9. php+js+return+true,js中return、return false、return true的区别

    1.语法及返回方式 ①返回控制与函数结果 语法为:return 表达式; 语句结果函数的执行,返回调用函数,而且把表达式的值作为函数结果返回出去 ②返回控制无函数结果 语法为:return; 在大多数 ...

最新文章

  1. 积木赛尔号机器人_赛尔号11年,圣灵谱尼从章鱼变花臂少年,最终成为了老父亲...
  2. Python调用MongoDB使用心得
  3. Docker 安装 Redis (Redis 配置)
  4. 洛谷1345 [Usaco5.4]奶牛的电信
  5. SQL必知必会-数据插入
  6. C语言中188 10取模等于多少,C语言编程:任取x为十进制整数,编程将x转换成对应的八进制数后输出。...
  7. 让cp显示进度的脚本
  8. 3大细节让新站SEO更有竞争优势
  9. 别人的Linux私房菜(19)认识与分析日志文件
  10. 通达OA应对后门检测的临时方法
  11. 机器人庄园作文_关于周庄一日游作文六年级汇总5篇
  12. 【MySQL数据库】- 多表查询
  13. [bzoj4199][NOI2015]品酒大会
  14. Java数组初始化, 冒泡排序, 查找
  15. Vue整合Element-UI的分页组件实现分页
  16. 富士通南大实习五月记
  17. linux修改主机名命令
  18. Chrome流量监控
  19. 从菜鸟到架构师(一)
  20. 一个 70 后运维老兵的 Elastic 认证工程师之路

热门文章

  1. 富士康员工涉嫌盗卖 iPhone 零件遭调查;风行网接手暴风;IntelliJ IDEA 2019.3.1 发布| 极客头条...
  2. DevOps 火爆,要学这么多技术!
  3. CSDN创始人蒋涛:开发者是泛终端生态的第一推动力
  4. 余承东吐槽苹果续航;微软 IE 浏览器被曝漏洞;React Native 0.61.0 发布 | 极客头条...
  5. 优秀的模糊测试代码是如何炼成的?
  6. 不写一行代码就能玩转 Kaggle 竞赛?
  7. 对 5G “迟钝”的苹果,该如何后来居上?| 极客头条
  8. 微软彻底告别移动操作系统!
  9. 谷歌返华或联手腾讯;华为否认5G专利收费;滴滴外挂让车费翻倍 | 极客头条...
  10. 爬了知乎 200 万数据,图说程序员都喜欢去哪儿工作