您的位置 首页 java

try-catch-finally 和 return 的执行顺序是什么样的?

之前看过一篇关于 return finally 执行顺序的文章,仅在 Java 的语言层面做了分析,其实我倒觉得直接看 bytecode 可能来的更清晰一点。

先看一个只有 try-finally ,没有 catch 的例子。

 public class DemoTryFinlly {
        public  void  tryFinally() {
            try {
                tryItOut();
            } finally {
                wrapItUp();
            }
        }
        
        public void tryItOut() {
        }
        public void wrapItUp() {

        }
    }
}  

通过 javap -c DemoTryFinlly 来查看它的字节码。

 public void DemoTryFinlly();
  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 DemoTryFinlly() {
  try {
    tryItOut();
    return;
  } finally {
    wrapItUp();
  }
}  

通过 javap -c DemoTryFinlly 来查看它的字节码。

 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。

给上面的代码加一个catch块

 public void DemoTryFinlly() {
  try {
    tryItOut();
  } catch (TestExc e) {
    handleExc(e);
  } finally {
    wrapItUp();
  }
}  
   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 和 return 的执行顺序是什么样的?

文章地址:https://www.zhihuclub.com/194801.shtml

关于作者: 智云科技

热门文章

网站地图