用bytecode来看try-catch-finally和return

之前看过一篇关于returnfinally执行顺序的文章,仅在Java的语言层面做了分析,其实我倒觉得直接看bytecode可能来的更清晰一点。

最近一直在看Java虚拟机规范,发现直接分析bytecode更能加深对Java语言的理解。

先看一个只有try-finally,没有catch的例子。

try - finally

public class ExceptionTest {
  public void tryFinally() {
    try {
      tryItOut();
    } finally {
      wrapItUp();
    }
  }

  // auxiliary methods
  public void tryItOut() { }

  public void wrapItUp() {}
}

通过javap -c ExceptionTest来查看它的字节码。

public void tryFinally();
  Code:
     0: aload_0
     1: invokevirtual #2  // Method tryItOut:()V
     4: aload_0
     5: invokevirtual #3  // Method wrapItUp:()V
     8: goto          18
    11: astore_1
    12: aload_0
    13: invokevirtual #3  // Method wrapItUp:()V
    16: aload_1
    17: athrow
    18: return
  Exception table:
     from    to  target type
         0     4    11   any

如果没有抛出异常,那么它的执行顺序为

0: aload_0
1: invokevirtual #2  // Method tryItOut:()V
4: aload_0
5: invokevirtual #3  // Method wrapItUp:()V
18: return

如果抛出了异常,JVM会在

Exception table:
   from    to  target type
       0     4    11   any

中进行控制跳转。如果是位于0到4字节之间的命令抛出了任何类型(any type)的异常,会跳转到11字节处继续运行。

11: astore_1
12: aload_0
13: invokevirtual #3
16: aload_1
17: athrow

astore_1会把抛出的异常对象保存到local variable数组的第二个元素。下面两行指令用来调用成员方法wrapItUp

12: aload_0
13: invokevirtual #3

最后通过

16: aload_1
17: athrow

重新抛出异常。

通过以上分析可以得出结论

在try-finally中,try块中抛出的异常会首先保存在local variable中,然后执行finally块,执行完毕后重新抛出异常。



如果我们把代码修改一下,在try块中直接return。

try - return - finally

public void tryFinally() {
  try {
    tryItOut();
    return;
  } finally {
    wrapItUp();
  }
}

”反汇编“一下:

 0: aload_0
 1: invokevirtual #2 // Method tryItOut:()V
 4: aload_0
 5: invokevirtual #3 // Method wrapItUp:()V
 8: return
 9: astore_1
10: aload_0
11: invokevirtual #3 // Method wrapItUp:()V
14: aload_1
15: athrow

可以看出finally块的代码仍然被放到了return之前。

如果try块中有return statement,一定是finally中的代码先执行,然后return。

JVM规范是这么说的

Compilation of a try-finally statement is similar to that of try-catch. Pior to transferring control outside the
try statement, whether that transfer is normal or abrupt, because an exception has been thrown, the
finally clause must first be execute.


try - catch - finally

给上面的代码加一个catch块

public void tryCatchFinally() {
  try {
    tryItOut();
  } catch (TestExc e) {
    handleExc(e);
  } finally {
    wrapItUp();
  }
}

javap一下

public void tryCatchFinally();
  Code:
     0: aload_0
     1: invokevirtual #2
     4: aload_0
     5: invokevirtual #3
     8: goto          31
    11: astore_1
    12: aload_0
    13: aload_1
    14: invokevirtual #5
    17: aload_0
    18: invokevirtual #3
    21: goto          31
    24: astore_2
    25: aload_0
    26: invokevirtual #3
    29: aload_2
    30: athrow
    31: return
Exception table:
   from    to  target type
       0     4    11   Class TestExc
       0     4    24   any
      11    17    24   any

通过Exception table可以看出:

  • catch监听 0 ~ 4 字节类型为TextExc的异常。
  • finally为 0 ~ 4 以及 11 ~ 17 字节任何类型的异常。

也就说 catch block 本身也在 finally block 的管辖范围之内。如果
catch block 中有 return statement,那么也一定是在
finally block
之后执行。


查看原文 http://www.liangfeizc.com/blog/article/32/

用bytecode来看try-catch-finally和return

时间: 2025-01-06 03:56:48

用bytecode来看try-catch-finally和return的相关文章

关于Java中try catch finally throw return的执行顺序问题

try {          normal statement;     //1.          exception occurred;   //2.          return "try";      } catch (Exception ex) {     normal statement;     //3.          return "catch";      } finally {          normal statement;     

try catch finally中return语句与非return语句的执行顺序问题

finally语句一定是会被执行的,不管前边的try块catch块中有无return语句,并且如果finally中存在return语句,这个return语句将会是最后执行的return语句,即函数最后的返回值.try,catch中的return并不是让函数直接返回,而是return语句执行完毕,把返回结果放到函数栈中,转而执行finally块,所以,若是finally中含有return语句,那么函数栈中的返回值将被刷新.看以下几种情况: 1:try有return,finally无 public

51.try块和catch块中return语句的执行

import java.util.Scanner; /** * 测试try块和catch块中return语句的执行. */ public class Test5 { public static void main(String[] args) { Scanner in = new Scanner(System.in); System.out.print("请输入被除数:"); try { int num1 = in.nextInt(); System.out.print("请

try,catch,finally和return执行顺序的知识点

   今天java学到try,catch,finally以及return的使用,刚开始模糊不清,后来也差不多清楚了,分享给大家,有什么问题谢谢指出.         try-catch是java中用来捕获异常的方法,也就是帮我们找到代码中存在的异常,其格式如下:   try{   代码段1      }   catch{   代码段2      }   代码段1是一段存在异常的代码,代码段2是处理代码段1异常的一些方法,当然可以有多个catch,表示同时提供多个处理代码段1异常的方法.(当代码段

关于Java里try/catch/finally/有return时执行过程

Java代码: public class Test1 {  public static void main(String[] args) {    int a=method1();    System.out.println("result----a="+a);} public static int method1(){  int a=0;  try {    a=1;    System.out.println("try----a="+a);    return

有return如果是try catch finally运行命令

背景: 昨天一个朋友出去采访,遇到这样的问题:"C#  catch那里return.finally也弄它运行?" 个人总结实践: 1.无论有木有出现异常.finally块中代码都会运行. 2.当try和catch中有return时,finally仍然会运行. 详细案比例如以下(此处以没有返回值的函数进行验证): 3.假设是值传递.finally中改变的值对try或catch块中return返回的值无影响.假设是引用类型參数(地址传递或对象),finally中的值改变对return会产生

有return的情况下try catch finally的执行顺序

http://www.cnblogs.com/lanxuezaipiao/p/3440471.html?cm_mc_uid=89442383850615035911861&cm_mc_sid_50200000=1505491196 1.不管有木有出现异常,finally块中代码都会执行:2.当try和catch中有return时,finally仍然会执行:3.finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么

有return的情况下try catch finally的执行顺序(最有说服力的总结)

结论:1.不管有木有出现异常,finally块中代码都会执行:2.当try和catch中有return时,finally仍然会执行:3.finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的:4.finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值.举例:情况1:try{}

在aardio的函数里try...catch语句中使用return。

try{ error("错误信息"); //使用error可以抛出一个错误 //如果error函数在try语句中,程序将不会报错,而会直接跳出try语句 } catch(e){ //如果try语句后跟catch语句则可以捕获到这个错误信息e } 以上是try...catch的语法: try语句尝试执行一个语句块,遇到错误则退出try语句块而不是中断aardio程序.如果使用了catch语句块就可以捕获异常(catch语句块是可选的). 以上是在aardio使用手册中的一段话. 也许在使