本文主要是介绍从字节码的角度来看try-catch-finally和return的执行顺序,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
从字节码的角度来看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_01: invokevirtual #2 // Method inside_try:()V4: aload_05: invokevirtual #3 // Method inside_finally:()V8: goto 3131: return
即先执行try里面的代码块,然后执行finally里面的代码块。
如果try中抛了一个异常,那么JVM会在如下的异常表中寻找跳转位置。
Exception table:from to target type0 4 11 Class java/lang/Exception0 4 24 any11 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_112: aload_013: aload_114: invokevirtual #5 // Method inside_catch:(Ljava/lang/E
xception;)V17: aload_018: invokevirtual #3 // Method inside_finally:()V21: goto 3131: return
astore_1会把抛出的异常对象保存到local variable数组的第二个元素。剩余的几行指令用来调用catch和finally块中的方法。
再看第二种情况:如果位于0到4字节之间的命令(即try块中的代码)抛出了任何类型的异常,则跳转到第24个字节开始执行finally中的代码
指令如下:
24: astore_225: aload_026: invokevirtual #3 // Method inside_finally:()V29: aload_230: athrow31: return
astore_2会把抛出的异常对象保存到local variable数组的第二个元素。下面的两行指令用来调用finally块中的方法。
25: aload_0
26: invokevirtual #3 // Method inside_finally:()V
最后通过如下的指令抛出异常
29: aload_230: 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块后面执行。
这篇关于从字节码的角度来看try-catch-finally和return的执行顺序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!