从字节码的角度来看try-catch-finally和return的执行顺序

来源:互联网 发布:西门子plc编程视频 编辑:程序博客网 时间:2024/06/07 07:04

从字节码的角度来看try-catch-finally和return的执行顺序

全篇以一个例子来说明:

先看如下的例子代码:

public class ExceptionTest {    public void  testException(){        try{            inside_try();        }        catch(Exception e){            inside_catch(e);        }        finally{            inside_finally();        }    }    //分别为try块、catch块和finally块中被调用的函数    public void inside_try(){   }    public void inside_catch(Exception e){  }    public void inside_finally(){}}

通过javap -c ExceptionTest命令可以看到此类的字节码如下:

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

 0: aload_0 1: invokevirtual #2                  // Method inside_try:()V 4: aload_0 5: invokevirtual #3                  // Method inside_finally:()V 8: goto          31 31: return

即先执行try里面的代码块,然后执行finally里面的代码块。

如果try中抛了一个异常,那么JVM会在如下的异常表中寻找跳转位置。

 Exception table:    from    to  target type        0     4    11   Class java/lang/Exception        0     4    24   any       11    17    24   any

从异常表中,可以看到有三种异常情况发生导致执行的路径不同:
第一种:如果位于0到4字节之间的命令(即try块中的代码)抛出了Class java/lang/Exception类型的异常,则跳转到第11个字节开始执行catch中的代码;
第二种:如果位于0到4字节之间的命令(即try块中的代码)抛出了任何类型的异常,则跳转到第24个字节开始执行finally里面的代码。
第三种:如果位于11到17字节之间的命令(即catch块中的代码)跑出了任何类型的异常,则跳转到第24个字节开始执行finally里面的代码。

先看第一种情况:如果位于0到4字节之间的命令(即try块中的代码)抛出了Class java/lang/Exception类型的异常,则跳转到第11个字节开始执行catch中的代码

指令如下:

      11: astore_1      12: aload_0      13: aload_1      14: invokevirtual #5                  // Method inside_catch:(Ljava/lang/Exception;)V      17: aload_0      18: invokevirtual #3                  // Method inside_finally:()V      21: goto          31      31: return

astore_1会把抛出的异常对象保存到local variable数组的第二个元素。剩余的几行指令用来调用catch和finally块中的方法。

再看第二种情况:如果位于0到4字节之间的命令(即try块中的代码)抛出了任何类型的异常,则跳转到第24个字节开始执行finally中的代码

指令如下:

  24: astore_2  25: aload_0  26: invokevirtual #3                  // Method inside_finally:()V  29: aload_2  30: athrow  31: return

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

25: aload_026: invokevirtual #3                  // Method inside_finally:()V

最后通过如下的指令抛出异常

29: aload_2  30: athrow

最后一种情况,如果位于11到17字节之间的命令(即catch块中的代码)跑出了任何类型的异常,则跳转到第24个字节开始执行finally里面的代码。

这种情况的代码与上面一样,直接执行finally块中的代码。

再来看下try和catch中有return语句的情形

例子代码如下,在catch块中有return语句:

public class ExceptionTest {    public void  testException(){        try{            inside_try();        }        catch(Exception e){            inside_catch(e);            return;//catch块中有return语句        }        finally{            inside_finally();        }    }    //分别为try块、catch块和finally块中被调用的函数    public void inside_try(){   }    public void inside_catch(Exception e){  }    public void inside_finally(){}}

用javap -c ExceptionTest命令查看字节码如下:

从字节码可以看出,即使try块中发生了异常,catch块中的return语句也是在finally块后面执行。

2 0
原创粉丝点击