关于java:trycatchfinally-和-return-是怎么执行的

34次阅读

共计 2488 个字符,预计需要花费 7 分钟才能阅读完成。

起源:http://liangfei.me/

最近始终在看 Java 虚拟机标准,发现间接剖析 bytecode 更能加深对 Java 语言的了解。

之前看过一篇对于 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_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 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: 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 之后执行。

近期热文举荐:

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

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

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

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

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

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0