trt catch finally 的字節(jié)碼分析

先上源碼:

public class TestRef {

    public static void main(String[] args) {
        int c = count(0, 20);
        System.out.println(c);
    }


    public static int count(int a, int b) {
        try {
            return add(a, b);
        } catch (RuntimeException e) {
            e.printStackTrace();
            return 0;
        } finally {
            System.out.println("回收資源");
        }
    }

    private static int add(int a, int b) {
        if (a == 0) {
            throw new RuntimeException();
        }
        return a + b;
    }
}

再看字節(jié)碼

{
  public static void main(java.lang.String[]);
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_0                  //將常量0推到棧頂
         1: bipush        20        //將直接操作數(shù)20 推到棧頂
         3: invokestatic  #2                  // Method count:(II)I 使用前2行推入的參數(shù)調(diào)用count靜態(tài)方法
         6: istore_1                       //將count方法的結(jié)果存到局部變量表1號位 
         7: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        10: iload_1                       
        11: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V 7、10、11三行是輸出count的結(jié)果
        14: return

  public static int count(int, int);
    Code:
      stack=2, locals=5, args_size=2
         0: iload_0        //加載局部變量表0號位到棧頂  靜態(tài)方法沒有this 局部變量表從0開始存
         1: iload_1        //加載局部變量表1號位到棧頂 
         2: invokestatic  #5                  // Method add:(II)I  調(diào)用靜態(tài)方法 add
         5: istore_2                //將棧頂元素存到局部變量表2號位,這里是存add結(jié)果
         6: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
         9: ldc           #6                  // String 回收資源
        11: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V 6、9、11三行是finally塊
        14: iload_2    //將局部變量2號位載入棧頂
        15: ireturn    //返回棧頂int類型元素 
        16: astore_2    //將對象引用存到局部變量表2號位
        17: aload_2      //加載局部變量表2號位的對象引用到棧頂
        18: invokevirtual #9                  // Method java/lang/RuntimeException.printStackTrace:()V
        21: iconst_0    //推送常量0到棧頂
        22: istore_3    //存儲棧頂元素到局部變量表3號位
        23: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        26: ldc           #6                  // String 回收資源  加載運行時常量池#6到棧頂
        28: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        31: iload_3    
        32: ireturn
        33: astore        4
        35: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        38: ldc           #6                  // String 回收資源
        40: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        43: aload         4
        45: athrow    //拋出異常
      Exception table:
         from    to  target type
             0     6    16   Class java/lang/RuntimeException
             0     6    33   any
            16    23    33   any
            33    35    33   any

  public static int add(int, int);
    Code:
      stack=2, locals=2, args_size=2
         0: iload_0 
         1: ifne          12   //如果棧頂元素小于0跳轉(zhuǎn)到12行
         4: new           #8                  // class java/lang/RuntimeException
         7: dup   //復(fù)制上一個元素。new對象后一般都有這一步。因為初始化對象會消耗一個引用
         8: invokespecial #10                 // Method java/lang/RuntimeException."<init>":()V
        11: athrow
        12: iload_0
        13: iload_1
        14: iadd
        15: ireturn
}

count方法相當?shù)膹?fù)雜 按順序看 是肯定不行的。 得結(jié)合Exception table異常表來看。異常表的順序是對應(yīng)catch的。from 0 to 6表示的是0-5這幾行,不含6的。

0-5行做的是add(a, b); 6-11行是finally塊 14,15行是返回add方法的值。這是沒有異常的時候的執(zhí)行流程。

異常表有2個from 0 to 6 的catch 第一個是我們定義的RuntimeException第二個是any 代表所有類型的異常。 這2個catch 的處理方法是不一樣的。target就是處理行開始。如果在0-5行發(fā)生運行時異常,就跳到16行處理。 16行 astore_2 將棧頂元素存儲到2號位,這里的棧頂元素是e 就是jvm傳入的異常對象的引用,16-32行 可以看做是一個塊,打印異常棧,調(diào)用finally返回元素0(0在調(diào)用finally 之前已經(jīng)存入了局部變量表,但是在執(zhí)行了finnaly之后才從局部變量表取出返回) 這里可以發(fā)現(xiàn)沒有使用任何的跳轉(zhuǎn)語句 比如 goto jsr ret 所以finally的代碼塊相當于重復(fù)了一次。

第三個catch from 16 to 23 這就是 catch (RuntimeException e) 里面的代碼,只是不含返回,如果這里發(fā)生了異常會跳轉(zhuǎn)到33行去執(zhí)行。33行是保存異常對象引用,然后35-40行又是finally的內(nèi)存,,然后43-45 就是把異常拋出到上層了。第三次重復(fù)finally

第四個catch是from 33 to 35,這中間只有一行代碼就是33的 astore 4 如果這行發(fā)生異常,會不斷的重試。不斷的跳回到33這行。成功后做的事情就和第三個catch一樣了。

第2、3、4 3個catch都是隱式的 幫我們做了 沒有用代碼寫出來的內(nèi)容:拋出未catch異常到上層

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,806評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,678評論 19 139
  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,871評論 0 10
  • Archlinux installation guidehttps://wiki.archlinux.org/in...
    sthtodo閱讀 1,773評論 1 6
  • 毛浴巾無色系陳列;在紗布和毛圈的區(qū)分之后,對毛巾做冷暖色系的區(qū)分陳列 衛(wèi)生巾縱向?qū)R,整齊度要加強 床品的疊裝有大...
    Holiday澈閱讀 456評論 0 0

友情鏈接更多精彩內(nèi)容