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

简介: 来源:http://liangfei.me/最近一直在看Java虚拟机规范,发现直接分析bytecode更能加深对Java语言的理解。之前看过一篇关于 return 和 finally 执行顺序的文章,仅在 Java 的语言层面做了分析,其实我倒觉得直接看 bytecode 可能来的更清晰一点。

来源:http://liangfei.me/


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


之前看过一篇关于 return 和 finally 执行顺序的文章,仅在 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 之后执行。


相关文章
每日一道面试题之try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
每日一道面试题之try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
175 0
|
7月前
|
编译器
try{...}catch(){...}finally{...}语句你真的理解吗?
try{...}catch(){...}finally{...}语句你真的理解吗?
38 0
try catch finally,try 里面有 return,finally 还执行吗?
try catch finally,try 里面有 return,finally 还执行吗?
79 0
16 # 实现 catch 方法
16 # 实现 catch 方法
62 0
try...catch中,catch加了return,后面的代码是不会执行的
try...catch中,catch加了return,后面的代码是不会执行的
112 0
|
Java
【学习笔记】【Java】try-catch-finally中,finally是在什么时候执行的:try结束、catch结束、return前
结论:try-catch-finally中,finally执行:try结束、catch结束、return前
203 0
【学习笔记】【Java】try-catch-finally中,finally是在什么时候执行的:try结束、catch结束、return前
|
Web App开发 JavaScript 前端开发
啊,似乎没有真正理解 try...catch...finally!
啊,似乎没有真正理解 try...catch...finally!
497 0
啊,似乎没有真正理解 try...catch...finally!
|
NoSQL Java 数据库连接
finally 和 return,到底谁先执行
经常有人面试被问到:finally 和 return,到底谁先执行呢?
|
C#
C# try catch finally
抛出异常开销非常大(相对而言),所以不要过多的在程序中使用它们 既然finally一定是要执行的,即使try块中有return
879 0

热门文章

最新文章