Java中try、catch、finally语句块的执行顺序(从字节码角度分析)

上篇文章从执行结果角度来看Java中try、catch、finally在各个场景下执行顺序,现在从字节码角度来再来看一遍:

1. try{return;}catch{}finally{} return;

1.1 源代码

public static int returnSttat(int i) {
    System.out.println("return block" + i);
    return i;
}

public static int test01() {
    int i = 0;
    try {
        i = 1;
        return returnSttat(i);
    }catch (Exception e) {

    } finally {
        System.out.println("finally block01");
    }
    return 0;
}

1.2 字节码

public static int test01();
    Code:
       0: iconst_0
       1: istore_0
       2: iconst_1
       3: istore_0
       4: iload_0
       5: invokestatic  #46                 // Method returnSttat:(I)I
       8: istore_3
       9: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      12: ldc           #48                 // String finally block01
      14: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      17: iload_3
      18: ireturn
      19: astore_1
      20: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      23: ldc           #48                 // String finally block01
      25: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      28: goto          42
      31: astore_2
      32: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      35: ldc           #48                 // String finally block01
      37: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      40: aload_2
      41: athrow
      42: iconst_0
      43: ireturn
    Exception table:
       from    to  target type
           2     9    19   Class java/lang/Exception
           2     9    31   any
          19    20    31   any

1.3 执行顺序分析
我们看第8~18行,我们可以从字节码命令看出在执行完try之后会将#3先存储起来,然后执行finally部分;最后将#3取出来返回给上层调用者.



2. try{}catch{}finally{} return 有异常场景;
2.1 源代码

public static int returnSttat(int i) {
    System.out.println("return block" + i);
    return i;
}
public static int test01() {
    int i = 1;
    int divid = 0;
    try {
        int n = i / divid;
    } catch (Exception e) {
        System.out.println("catch block");
        return returnSttat(i);
    } finally {
        System.out.println("finally block");
    }
    return 0;
}

2.1 字节码

public static int test01();
    Code:
       0: iconst_1
       1: istore_0
       2: iconst_0
       3: istore_1
       4: iload_0
       5: iload_1
       6: idiv
       7: istore_2
       8: goto          48
      11: astore_2
      12: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      15: ldc           #46                 // String catch block
      17: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: iload_0
      21: invokestatic  #48                 // Method returnSttat:(I)I
      24: istore        4
      26: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      29: ldc           #50                 // String finally block
      31: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      34: iload         4
      36: ireturn
      37: astore_3
      38: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      41: ldc           #50                 // String finally block
      43: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      46: aload_3
      47: athrow
      48: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      51: ldc           #50                 // String finally block
      53: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      56: iconst_0
      57: ireturn
    Exception table:
       from    to  target type
           4     8    11   Class java/lang/Exception
           4    26    37   any
}

2.3 执行顺序分析
我们直接从第6行看idiv指令抛出异常,1) 根据Exception Table取[4, 8, 11, Class java/lang/Exception]指令跳转到11开始执行; 2) 从11~21行均为catch块代码执行; 3) 行24将catch中return值记录在4中; 4)执行finally部分;5)取出4的值然后返回给调用方.



3. try{return;} catch{} finally{return;};
3.1 源代码

public static int returnSttat(int i) {
    System.out.println("return block" + i);
    return i;
}
public static int test01() {
    int i = 1;
    try {
        System.out.println("try block");
        return returnSttat(i);
    } catch (Exception e) {
        System.out.println("catch block");
    }finally {
        System.out.println("finally block");
        return returnSttat(0);
    }
}

3.2 字节码

public static int test01();
    Code:
       0: iconst_1
       1: istore_0
       2: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       5: ldc           #46                 // String try block
       7: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      10: iload_0
      11: invokestatic  #48                 // Method returnSttat:(I)I
      14: pop
      15: goto          31
      18: astore_1
      19: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      22: ldc           #50                 // String catch block
      24: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      27: goto          31
      30: pop
      31: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      34: ldc           #52                 // String finally block
      36: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      39: iconst_0
      40: invokestatic  #48                 // Method returnSttat:(I)I
      43: ireturn
    Exception table:
       from    to  target type
           2    18    18   Class java/lang/Exception
           2    27    30   any
}

3.3 执行顺序分析
我们可以看到1~14行为执行try块命令;1)15行通过goto语句跳转到31行(finally块); 2) 执行finally块,我们重点看40,43行,finally中执行了方法后就调用了ireturn指令,我们可以以此看出返回给调用方的是finally中return的语句的值(快速返回)

扫描二维码关注公众号,回复: 2647035 查看本文章


4. try{return;} catch{} finally{return;}有异常
4.1 源代码

public static int returnSttat(int i) {
    System.out.println("return block" + i);
    return i;
}
public static int test01() {
    int i = 1;
    int j = 0;
    try {
        System.out.println("try block");
        int k = i / j;
        return returnSttat(i);
    } catch (Exception e) {
        System.out.println("catch block");
        return returnSttat(-1);
    }finally {
        System.out.println("finally block");
        return returnSttat(0);
    }
}

4.2 字节码

public static int test01();
    Code:
       0: iconst_1
       1: istore_0
       2: iconst_0
       3: istore_1
       4: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       7: ldc           #46                 // String try block
       9: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      12: iload_0
      13: iload_1
      14: idiv
      15: istore_2
      16: iload_0
      17: invokestatic  #48                 // Method returnSttat:(I)I
      20: pop
      21: goto          42
      24: astore_2
      25: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      28: ldc           #50                 // String catch block
      30: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      33: iconst_m1
      34: invokestatic  #48                 // Method returnSttat:(I)I
      37: pop
      38: goto          42
      41: pop
      42: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
      45: ldc           #52                 // String finally block
      47: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      50: iconst_0
      51: invokestatic  #48                 // Method returnSttat:(I)I
      54: ireturn
    Exception table:
       from    to  target type
           4    24    24   Class java/lang/Exception
           4    41    41   any
}

4.3 执行顺序分析
我们从第14行看执行idiv出现异常; 1) 根据Exception Table可以确定跳转到24行继续执行;2) 24~37行执行catch快部分; 3) 38行跳转到finally部分执行,我们重点看51,54行在finally中执行了静态方法后就调用了ireturn,实际上这调用返回的是finally中return表达式的结果



二、总结
从执行现象上看是可以得到上一篇文章对于执行顺序的结论,然而我只是深深的记住了这个结果,这从字节码的角度再来看一遍,对于try、catch、finally的执行顺序就一目了然了.

猜你喜欢

转载自blog.csdn.net/cockroach02/article/details/80226651