转载: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. Linux iptables 防火墙详解

    0x00 iptables介绍 linux的包过滤功能,即linux防火墙,它由netfilter 和 iptables 两个组件组成. netfilter 组件也称为内核空间,是内核的一部分,由一些 ...

  2. MAC 系统升级10.10以后PHP验证码错误的解决办法。[ 一行代码轻松解决! ]

    MAC 升级到10.10 以后PHP版本为5.5,初步判定是由于FreeType 字体库的原因,导致GD库有些问题,总之就是验证码出不来.很多大牛给出的办法是重新编译PHP,这对于手头有项目的人来说可 ...

  3. typedef和block

    为block类型对象取别名 1.没有使用typedef的情况 int (^block_add)(int, int) = ^(int value1, int value2) { return value ...

  4. bzoj1562【Noi2009】变换序列

    题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1562 给一个序列Di表示min(|i-Ti|,n-|i-Ti|),求一个字典序最小的序列Ti ...

  5. nginx keepalived 主从切换

    注:  LVS + Keepalived  不知道为什么出现一个很郁闷的问题....... ------------------------------------------------------ ...

  6. mysql问题: alter导致速度慢

    1 如何并行执行. 数据库里有一个数据量非常大的表,当对这个表进行alter的时候,这时候该表是只读的,由于数据量很大alter时间很长,如果这时候有insert或update操作,有什么办法在这期间 ...

  7. PHP 判断几秒前,几分钟,几小时前

    PHP 对于时间的过了多久的判断,几秒前,几分钟前,几小时前,$time = strtotime("2017-01-15 14:42:00"); $time = strtotime ...

  8. Codeforces#362

    A题 题意:给定一串数列,t,t+s,t+s+1,t+2s,t+2s+1......问某一个数是否是数列当中的 题意:只需判断(x-t)与(x-t-1)能否整除s即可,注意起始时的判断 #includ ...

  9. STM32的USART DMA传输(转)

    源:STM32的USART DMA传输 问题描述: 我有一个需求,AD采得一定数目的数据之后,由串口DMA发出,由于AD使用双缓冲,所以每次开始DMA的时候都需要重新设置开始的内存地址以及传输的数目( ...

  10. USB入门基础知识(转)

    源:USB入门基础知识 相关名词: 主机(Host) 设备(Device) 接口(Interface) 管道(Pipe) 管道是主机与设备端点数据传输的连接通道,代表了主机的数据缓冲区与设备端点之间交 ...