转载:http://blog.csdn.net/sureyonder/article/details/5560538

Java虚拟机在每个try语句块和与其相关的catch子句的结尾 处都会“调用”finally子句的子例程。实际上,finally子句在方法内部的表现很象“微型子例程”。finally子句正常结束后-指的是finally子句中最后一条语句正常执行完毕,不包括抛出异常,或执行return、continue、break等情况,隶属于这个finally子句的微型子例程执行“返回”操作。程序在第一次调用微型子例程的地方继续执行后面的语句。

finally“微型子例程”不等同于方法函数的调用,finally子句都是在同一个栈内执行的,微型子例程的“返回”操作也不会涉及到方法退栈,仅仅是使程序计数器pc跳转到同一个方法的一个不同的位置继续执行。

一 异常丢失

  1. public static void exceptionLost()
  2. {
  3. try
  4. {
  5. try
  6. {
  7. throw new Exception( "exception in try" );
  8. }
  9. finally
  10. {
  11. throw new Exception( "exception in finally" );
  12. }
  13. }
  14. catch( Exception e )
  15. {
  16. System.out.println( e );
  17. }
  18. }

exceptionLost()的输出结果是“exception in finally”,而不是try块中抛出的异常,这是JAVA异常机制的一个瑕疵-异常丢失。

在字节码中,throw语句不是原子性操作。在较老的JDK中,exceptionLost()中try块的throw语句分解为几步操作:

1) 把Exception("exception in try")对象引用存储到一个局部变量中
  astore_2  // pop the reference to the thrown exception, store into local variable 2
2) 调用finally微型子程序
3) 把局部变量中的Exception("exception in try")对象引用push到操作数栈顶,然后抛出异常
  aload_2  // push the reference to the thrown exception from local variable 2

  athrow   // throw the exception

如果finally通过break、return、continue,或者抛出异常而退出,那么上面的第3步就不会执行。

在JDK1.6中,通过字节码我们可以看到,finally子句作为一种特殊的catch来实现的,下面是exceptionLost()方法的异常表:

Exception table:
  from   to   target  type
   0     10    10     any
 0     21    21     Class java/lang/Exception

finally可以捕获从0行到9行之间抛出的任何类型(any)的异常,并重新抛出捕获的异常,或者抛出一个自己构造的新异常,这个新异常就会覆盖try语句块中的异常。

二 返回值覆盖

  1. public static int getValue()
  2. {
  3. int value = 0;
  4. try
  5. {
  6. value = 100;
  7. return value;
  8. }
  9. finally
  10. {
  11. value = 200;
  12. }
  13. }

这个方法的返回值是100还是200?结果是100。
在字节码中,return语句不是原子性操作,它会把getValue()中的return语句分解为几步操作:
1) 把value值存储到一个局部变量(这里命名为temp)中:
   iload_0   // push local variable 0 - the 100
   istore_2   //  pop an int (the 100), store into local varaible 2
2) 调用finally微型子程序
3) 把局部变量(指temp)的值push到操作数栈顶,然后返回到调用方法
     iload_2  // push local varaible 2 - the 100
   ireturn      // return int on top of the stack - the 100: return 100

由于return语句在返回之前会把返回值保存到一个临时的局部变量中,所以在finally子句内对value重新赋值不会影响返回值。

了解finally子句内在的一些知识,我们能够了解finally能够做什么和不能够做什么,这样会帮助我们正确使用finally子句。

JAVA finally字句的异常丢失和返回值覆盖解析的更多相关文章

  1. Java异常处理场景中不同位置的返回值详细解析

    Java 异常处理中的返回值在不同位置不同场景下是有一些差别的,这里需要格外注意 具体分以下两种场景: 1 finally语句块没有return语句,即当代码执行到try或者catch语句块中的ret ...

  2. JAVA中执行JavaScript代码并获取返回值

    JAVA中执行JavaScript代码并获取返回值 场景描述 实现思路 技术要点 代码实现 测试方法 运行结果 改进空间 场景描述 今天在CSDN上偶然看到一个帖子对于一段字符串 “var p=‘xx ...

  3. Java和Ibatis调用存储过程并取得返回值详解

    Java和Ibatis调用存储过程并取得返回值详解 2011-07-19 17:33 jiandanfeng2 CSDN博客 字号:T | T 本文主要介绍了Java和Ibatis调用存储过程的方法, ...

  4. 为什么阿里巴巴Java开发手册中强制要求接口返回值不允许使用枚举?

    在阅读<阿里巴巴Java开发手册>时,发现有一条关于二方库依赖中接口返回值不允许使用枚举类型的规约,具体内容如下: 在谈论为什么之前先来科普下什么是二方库,二方库也称作二方包,一般指公司内 ...

  5. .net单元测试——常用测试方式(异常模拟、返回值测试、参数测试、数据库访问代码测试)

    最近在看.net单元测试艺术,我也喜欢单元测试,今天介绍一下如何测试异常.如何测试返回值.如何测试模拟对象的参数传递.如何测试数据库访问代码.单元测试框架使用的是NUnit,模拟框架使用的是:Rhin ...

  6. Java中能否利用函数参数来返回值

    转自https://blog.csdn.net/da_da_xiong/article/details/70039532 我们在写代码时通常会遇到一种情况,就是我们可能希望在一个函数操作完成后返回两个 ...

  7. Java反射机制二 获取方法的返回值或参数的泛型信息

    在使用反射机制时,我们经常需要知道方法的参数和返回值类型,很简单  ,下面上示例,示例中的两个方法非常相似 package deadLockThread; import java.lang.refle ...

  8. Java - 关于基础数据类型的形参和返回值

    1. 当基础数据类型被当作形参时,最好使用其包装类,因为这样可方便调用者传参(基础数据类型亦或是其包装类都可)   2. 当基础数据类型被当作返回值时,最好使用原型,因为这样可以方便调用者接收返回值( ...

  9. Java 8新特性--Lambda表达式作为返回值

    lambda表达式作为方法的返回值:

随机推荐

  1. 搭建git服务器及利用git hook自动布署代码

    注意:服务器:Ubuntu Server 14.04,我的项目比较小,所有操作都使用root,建议最好新建一个用户(需要有管理员权限,否则在后面使用hooks自动部署代码时会出现各种权限问题,很蛋疼的 ...

  2. Hibernate与IBatis的优缺点及可行性分析

    以下文章来源于考试大 1.优点 简单: 易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现. 实用: 提供了数据映射功能,提供了对底层数据访问的封装(例如ado.net),提供 ...

  3. Mybatis 示例之 Association - 偶尔记一下 - 博客频道 - CSDN.NET

    body { font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI ...

  4. (干货)一次httpclient的close_wait问题的探讨

    从图中可以看出,如果客户端被动关闭连接,且没有向服务器端发送FIN,则会一直处于CLOSE_WAIT状态. 处理服务器在处理完请求,与后端Nginx之间的连接仍然保持着CLOSE_WAIT状态,个数为 ...

  5. 基于keepalived 实现VIP转移,lvs,nginx的高可用

    转自:http://www.tuicool.com/articles/eu26Vz 一.Keepalived 高可用集群的解决方案 二.VRRP的有限状态机 三.利用keepalived 实现主从VI ...

  6. CKeditor使用js验证不得为空

    if (CKEDITOR.instances.TextArea1.getData() == '') { alert('警告:详细内容不得为空!'); CKEDITOR.instances.TextAr ...

  7. INC函数

    1.inc(integer) inc(a)等于a:=a+1; 例: i := 100; inc(i); 结果:i等于101 2.inc(integer,integer) inc(a,b)等于a:=a+ ...

  8. Object类可以接受引用类型

    Object类是一切类的父类,所以Object类可以接受一切引用类型.连数组和接口对象也都可以接受. 1.接受数组 public class ObjectTest{ public static voi ...

  9. Bzoj3473

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3473 题解:待更 代码:待更 开始时间: 结束时间:

  10. 为什么delphi控件前面都有t

    控件的类名都有一个T字, 它是Type的第一个字母. 比如按钮就是TButton. 但在Delphi的控件面板上的并不带T字, 比如就是Button. 如果你把它放在窗体上, 默认名字则成为Butto ...