zoukankan      html  css  js  c++  java
  • try-catch-finally 和 return 是怎么执行的?

    来源: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开发手册(嵩山版)》最新发布,速速下载!

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

  • 相关阅读:
    关于 省赛模拟赛(迪迦桑专场)
    ZOJ3878: Convert QWERTY to Dvorak(浙江省赛2015)
    Is It A Tree?
    Escape
    关于细节
    [UE4]AnimDynamics简介
    [UE4]武器碰撞
    [UE4]CustomAnimationBlueprintNode 自定义动画蓝图节点
    百钱买白鸡
    asp.net 标准控件的重要属性
  • 原文地址:https://www.cnblogs.com/javastack/p/14819062.html
Copyright © 2011-2022 走看看