2021年5月27日星期四

try-catch-finally 和 return 是怎么执行的?

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

先看一个只有 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_01: invokevirtual #2 // Method tryItOut:()V4: aload_05: invokevirtual #3 // Method wrapItUp:()V18: return

如果抛出了异常,JVM 会在

Exception table: from to target type  0  4 11 any

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

11: astore_112: aload_013: invokevirtual #316: aload_117: athrow

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

12: aload_013: invokevirtual #3

最后通过

16: aload_117: 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_110: aload_011: invokevirtual #3 // Method wrapItUp:()V14: aload_115: 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 thetry statement, whether that transfer is normal or abrupt, because an exception has been thrown, thefinally 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: returnException 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 之后执行。

近期热文推荐:

1.600+ 道 Java面试题及答案整理(2021最新版)

2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!

3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!

4.Spring Cloud 2020.0.0 正式发布,全新颠覆性版本!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!









原文转载:http://www.shaoqun.com/a/763869.html

跨境电商:https://www.ikjzd.com/

巴士物流:https://www.ikjzd.com/w/2329

拍怕网:https://www.ikjzd.com/w/2205


来源return和finally执行顺序的文章,仅在Java的语言层面做了分析,其实我倒觉得直接看bytecode可能来的更清晰一点。先看一个只有try-finally,没有catch的例子。try-finallypublicclassExceptionTest{publicvoidtryFinally(){try{tryItOut();}finally{wrapItUp();}}//auxili
勤商网:https://www.ikjzd.com/w/2219
easy buy:https://www.ikjzd.com/w/2162
斑马物联:https://www.ikjzd.com/w/1316
32家中国企业被判侵权!亚马逊选品如何避免侵权?:https://www.ikjzd.com/articles/572
2019跨境电商新蓝海,只需3分钟带你快速了解亚马逊清晰思路:https://www.ikjzd.com/articles/19396
新平台的崛起?英国电商平台OnBuy发展迅猛,产品数已超800多万!:https://www.ikjzd.com/articles/9695

没有评论:

发表评论