问题

在Java的异常体系中,我们经常会使用finally语句块来保证进行一些无论有无异常都要执行的处理流程,但finally语句块与return语句究竟哪个先执行总是让人迷惑。根据书本介绍,似乎是finally先于return执行,但原理又是什么呢?

分析

请看下面这段代码,考虑test方法的返回值在出现异常和不出现异常的情况下分别是多少?

static int test() {

int x;

try {

x = 1;

return x;

} catch (Exception e) {

x = 2;

return x;

} finally {

x = 3;

}

}

稍有经验的Java程序都可以看出:如果没有异常,则返回1;如果出现了Exceptioin异常,则返回2;如果出现了Exception以外的异常,则方法非正常退出,没有返回值。

下面我们使用javap命令将编译得到的class文件反汇编,看一下我们的示例程序生成的字节码是什么样子的,进而对其分析。

其中test方法部分的字节码如下所示:

static int test();

Code:

Stack=1, Locals=4, Args_size=0

0: iconst_1// 将int类型的1压至栈顶

1: istore_0// 将栈顶int型数据存入第一个本地变量; 即try块中的x=1

2: iload_0// 将第一个int型本地变量压至栈顶

3: istore_3// 将栈顶int型数值存入第四个本地变量(最后一个)

4: iconst_3// 将int型3压至栈顶

5: istore_0// 将栈顶int型数据存入第一个本地变量; 即finally块中的x=3

6: iload_3// 将第四个int型本地变量压至栈顶

7: ireturn// 将栈顶int型数值返回

8: astore_1// 将栈顶引用型数值存入第二个本地变量

9: iconst_2// 将int类型的2压至栈顶

10: istore_0// 将栈顶int型数据存入第一个本地变量; 即catch块中的x=2

11: iload_0// 见第2行

12: istore_3// 见第3行

13: iconst_3// 见第4行

14: istore_0// 见第5行

15: iload_3// 见第6行

16: ireturn// catch语句块中的return

17: astore_2// try中出现不属于Exception或其子类的异常或者catch中出现异常;将异常存入第3个本地变量

18: iconst_3// finally中的x=3

19: istore_0

20: aload_2// 将第3个本地变量中的异常压入栈顶

21: athrow// 抛出异常

Exception table:

from to target type

0 4 8 Class java/lang/Exception

0 4 17 any

8 13 17 any

首先看一下方法的异常表信息,也就是字节码中的Exception table部分。异常表中生成了三条记录,对应三条可能出现的代码执行路径:

第0至4行出现Exception异常,则程序跳到第8行开始执行;对应try语句块中出现属于Exception或其子类异常,则转到catch语句块处理。

第0至4行出现不属于Exception或其子类的异常,程序跳到第17行处理;对应try语句块中出现不不属于Exception或其子类的异常,程序跳到finally语句 块处理。

第8到13行出现任何异常,程序跳到第17行处理;对应catch语句块中出现任何异常,程序转到finally语句块处理。

如字节码中的注释所示,字节码中第0至4行(不包括第4行)所做的操作就是将整数1赋值给变量x,并且将此时x的值复制一份到最后一个本地变量表的Slot中(该Slot里的值在ireturn指令执行前会被重新读取并压至操作数栈顶,作为方法返回值来使用。这里将Slot标记为returnValue)。如果这时没有发生异常,程序继续往下运行第4至7行,也就是finally语句块中的代码,在这里将x赋值为3,然后将之前保存在returnValue(最后一个Slot)中的整数1读入到操作数栈顶,最后ireturn指令会以int形式返回操作数栈顶中的值,方法结束。

如果在try语句块中出现了Exception异常,程序跳到第8行。第8到13行所做的事情就是将2赋值给变量x,然后将x此时的值复制一份给returnValue(第12行),然后执行finally语句块将变量x的改为3(第13、14行)。方法返回前(ireturn指令,第16行)同样是将returnValue中存储的整数2读到操作栈顶以int形式返回,方法结束。

第17行之后的代码是在上面三条异常表记录中后两条情况下要处理的字节码,也就是在catch语句块中出现异常或者在try语句块中出了不属于Exception或其子类异常的情况下。所做的操作也就是将变量x的值改为3,并将异常对象的引用压入操作栈顶并抛出,方法结束。

结论

finally中的语句在任何情况下都要处理,从上面字节码可以看到,三条可能流程都有finally子句对应的指令(分别为第4、5行;第13、14行;以及第18、19行);

finally是在return语句之前执行的,第7行和16行分别对应try和catch中的return语句,都在finally对应的字节码指令之后可以证明;

finally语句中对返回值的修改并不会真正被返回。以catch中的return为例,在执行finally字节码指令前(第3行),将返回值存入本地变量最后一个Slot(简称为returnValue)中,而finally语句只是改变了局部变量x的值(第4、5行),并没有改变returnValue中的值,然后在执行ireturn指令前,将returnValue中的值压至栈顶(第6行)),ireturn指令将其返回(第7行)。

finally在java程序中的作用_深入理解Java中的finally相关推荐

  1. java 注解处理器的作用_深入理解Java:注解(Annotation)--注解处理器

    如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了.使用注解的过程中,很重要的一部分就是创建于使用注解处理器.Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处 ...

  2. java虚引用作用_深入理解Java中的引用(二)——强软弱虚引用

    深入理解Java中的引用(二)--强软弱虚引用 在上一篇文章中介绍了Java的Reference类,本篇文章介绍他的四个子类:强引用.软引用.弱引用.虚引用. 强引用(StrongReference) ...

  3. java程序包不存在_第一章 Java语言简介

    Java语言简介 Java之父 James Gosling(詹姆斯·高斯林) 正式诞生时间 1995年,已有二十多年历史 三大方向 JavaSE(桌面版,基础需重点掌握) JavaME(移动版,现在基 ...

  4. 范数在机器学习中的作用_设计在机器学习中的作用

    范数在机器学习中的作用 Today, machine learning (ML) is a component of practically all new software products. Fo ...

  5. 统计信息在数据库中的作用_统计在行业中的作用

    统计信息在数据库中的作用 数据科学与机器学习 (DATA SCIENCE AND MACHINE LEARNING) Statistics are everywhere, and most indus ...

  6. java 中的流_深入理解Java中的流(Stream)

    首先,流是什么? 流是个抽象的概念,是对输入输出设备的抽象,Java程序中,对于数据的输入/输出操作都是以"流"的方式进行.设备可以是文件,网络,内存等. 流具有方向性,至于是输入 ...

  7. python在平面设计中的作用_图像处理在平面设计中的作用

    图像处理在平面设计中的作用 处在风华正茂的我们站在 20 出头的路上,退出了懵懵懂懂的少年时光,开始露出了充 满活力与未来的青年锋芒. 我们经历了短暂而铭心的艺考, 完成了难忘的高考时光, 我们有 过 ...

  8. 什么是java程序的主类_什么是Java 应用程序的主类?

    问题阐述 在进行Java 应用程序开发时,为了使应用程序能够运行,这个应用程序必须要含有一个主类,请问什么是Java 应用程序的主类? 专家解答 Java 应用程序是由若干类和接口组成的,为了使Jav ...

  9. java程序试岗内容_使用纯 Java 程序为 SQL Server 数据库加载 JDBC 驱动程序,使用()语句...

    [单选题]如果在导游讲解进程中发生意外情况,景区(点)讲解员应及时联络( ),以期尽快得到妥善处理或解决. [多选题]与图文声像导游方式相比,实地口语导游方式将始终处于主导地位的原因有( ). [单选 ...

最新文章

  1. 《游戏力》读书笔记作文4700字
  2. Mybatis报错 TooManyResultsException
  3. python基础(part13)--包
  4. 安卓dts音频解码_家庭影院三维音效技术应用之DTS:X摆位
  5. Redis集群模式部署
  6. html 图片隐藏 一部分,如何在HTML / CSS中仅显示图像的一部分?
  7. Java中的锁---队列同步器
  8. mysql -d -e_mysql常用函数
  9. ReactiveCocoa MVVM 学习总结二
  10. 福利 | 国外最牛逼的一套 PPT 作品送给你
  11. win10电脑桌面html,手把手教你美化win10电脑桌面的小技巧
  12. linux彻底清除历史记录
  13. Web开发技术课程设计
  14. java计算机毕业设计物流公司停车位管理源程序+mysql+系统+lw文档+远程调试
  15. You must have administrator privileges to run...
  16. Login 和 Logout
  17. apollo新增扩展consul注册中心
  18. 【5G架构】5G 接入网架构概述
  19. 数字 IC 设计、FPGA 设计秋招笔试题目、答案、解析(1)2022 紫光展锐(上)
  20. HAUT OJ 1231: ykc买零食

热门文章

  1. linux安装指南,ttyLinux安装完整指南
  2. 41.设置windows系统字体CreateFont、CreateFontIndirect、GetStockObject
  3. C++和qt designer的混合编程--动态计算加法小工具
  4. AMD CPU polybar温度不正确
  5. 不安装任何软件,能否在线查看CAD图纸
  6. 计算机网络的研究进展和趋势,数据中心网络研究进展和趋势.PDF
  7. 请给我写信——教你使用简洁漂亮的网易邮件接口
  8. oracle优化:instr做join条件很慢
  9. 【Android】用Cubism 2制作自己的Live2D——android sdk样本的下载与Android studio编译!...
  10. 刘国军:异构融合加速赋能数字化升级