java中return finally_Java中return和finally到底哪个先执行
本章节我们从字节码的角度来探究下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到底哪个先执行相关推荐
- java 异常 return_Java异常处理中同时有finally和return语句的执行问题
在Java中当try.finally语句中包含return语句时,执行情况到底是怎样的,finally中的代码是否执行,大家众说纷纭,有的说会执行,有的说不会执行,到底哪种说法正确,现在通过下面的例子 ...
- java异常处理:finally中不要return
java异常处理:finally中不要return 参考文章: (1)java异常处理:finally中不要return (2)https://www.cnblogs.com/Fskjb/archiv ...
- 你真的了解try{ return }finally{}中的return?
你真的了解try{ return }finally{}中的return? 今天去逛论坛 时发现了一个很有趣的问题: 谁能给我我解释一下这段程序的结果为什么是:2.而不是:3 代码如下: class T ...
- JavaScript 中的return true 和return false
2019独角兽企业重金招聘Python工程师标准>>> 1.对于return true 和 return false: return false表示返回一个false值,也就是说提交 ...
- Sql Server 中存储过程的output return的区别
看http://zxianf.blog.163.com/blog/static/301207012009114104124969/中片关于Sql Server中存储过程output和return值的区 ...
- php 类中调用另类,PHP return语句另类用法不止是在函数中,return语句_PHP教程
PHP return语句另类用法不止是在函数中,return语句 分享下PHP return语句的另一个作用,在bbPress的代码中看到的一个奇葩使用方法. 一直以为,return只能出现在函数中, ...
- vue中的data用return返回
为什么在大型项目中data需要使用return返回数据呢? 答:不使用return包裹的数据会在项目的全局可见,会造成变量污染:使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件. ...
- JavaScript 中,break , continue , return 的区别
break , continue , return 的区别 break :结束当前的循环体(如 for.while) continue :跳出本次循环,继续执行下次循环(如 for.while) re ...
- php+js+return+true,js中return、return false、return true的区别
1.语法及返回方式 ①返回控制与函数结果 语法为:return 表达式; 语句结果函数的执行,返回调用函数,而且把表达式的值作为函数结果返回出去 ②返回控制无函数结果 语法为:return; 在大多数 ...
最新文章
- 积木赛尔号机器人_赛尔号11年,圣灵谱尼从章鱼变花臂少年,最终成为了老父亲...
- Python调用MongoDB使用心得
- Docker 安装 Redis (Redis 配置)
- 洛谷1345 [Usaco5.4]奶牛的电信
- SQL必知必会-数据插入
- C语言中188 10取模等于多少,C语言编程:任取x为十进制整数,编程将x转换成对应的八进制数后输出。...
- 让cp显示进度的脚本
- 3大细节让新站SEO更有竞争优势
- 别人的Linux私房菜(19)认识与分析日志文件
- 通达OA应对后门检测的临时方法
- 机器人庄园作文_关于周庄一日游作文六年级汇总5篇
- 【MySQL数据库】- 多表查询
- [bzoj4199][NOI2015]品酒大会
- Java数组初始化, 冒泡排序, 查找
- Vue整合Element-UI的分页组件实现分页
- 富士通南大实习五月记
- linux修改主机名命令
- Chrome流量监控
- 从菜鸟到架构师(一)
- 一个 70 后运维老兵的 Elastic 认证工程师之路
热门文章
- 富士康员工涉嫌盗卖 iPhone 零件遭调查;风行网接手暴风;IntelliJ IDEA 2019.3.1 发布| 极客头条...
- DevOps 火爆,要学这么多技术!
- CSDN创始人蒋涛:开发者是泛终端生态的第一推动力
- 余承东吐槽苹果续航;微软 IE 浏览器被曝漏洞;React Native 0.61.0 发布 | 极客头条...
- 优秀的模糊测试代码是如何炼成的?
- 不写一行代码就能玩转 Kaggle 竞赛?
- 对 5G “迟钝”的苹果,该如何后来居上?| 极客头条
- 微软彻底告别移动操作系统!
- 谷歌返华或联手腾讯;华为否认5G专利收费;滴滴外挂让车费翻倍 | 极客头条...
- 爬了知乎 200 万数据,图说程序员都喜欢去哪儿工作