finally 語句塊是否一定會被執行?


結論

結論:不一定,存在兩種可能的情況。第一種,調用了 System.exit,第二種,finally 語句位於一個線程中,但是這個線程隨着主線程的終結而終結了。代碼請看 example1.另外值得注意的是,即使在 try 中 return 了,還是會執行后面的 finally。

代碼:

輸出:

原理

那 try, catch, finally 是如何實現的呢?下面我們用反匯編看看。

反匯編命令 javap -c -p Example1.class,完整的反匯編代碼放到了最后。

異常表

我們可以看到在 test 函數的最后,有一個異常表。表頭有四列,from to target type。一共有三行。第一行是 try 語句塊中,如果發生 Exception 這個異常,那么將跳轉到第 48 行執行。第二,第三行,跳轉到 finally 中去執行。

那這個 any 是什么呢?如果還沒有看反匯編的代碼,你可能會覺得這就是 finally 的實現原理了,執行完 try/catch 塊之后就跳轉到 finally 語句塊去執行。可是,看看反匯編的代碼,就會發現這個函數中,有三個 finally 語句塊!在 try 后面有一個,在 catch 后面還有兩個。所以,這里我猜是除了 catch 之外的其他異常,如果在 try 和 catch 中發生了沒有捕獲的異常,那么就去執行 finally 語句塊。

原理

通過分析后面的反匯編代碼,我們可以看出來:

  1. finally 基本都是要執行的,除非暴力的 System.exit 或者線程提前終結了。
  2. catch 的實現方法是異常表。多個 try...catch,嵌套的 try...catch 共用一個異常表,不同方法不共用異常表。這個你可以檢驗一下。
  3. try 即使 return,finally 都還執行的原因,是 java 在編譯的時候,在 try 語句塊的 return 之前插入代碼。而且,return 的內容可以被 finally 的 return 覆蓋。
  4. try, catch 沒有捕獲的異常,會在 finally 中拋出,athrow 指令。所以不要在 finally 中 return,否則這些沒有捕獲的異常將不會被拋出。

完整的反匯編代碼。

Compiled from "Example1.java"

public class example.Example1 {
  public example.Example1();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method test:()Lexample/Example1$Apple;
       3: astore_1
       4: aload_1
       5: invokevirtual #3                  // Method example/Example1$Apple.show:()V
       8: return

  private static example.Example1$Apple test();
    Code:
       0: iconst_0
       1: istore_0
       2: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       5: ldc           #5                  // String ִ���� try ����
       7: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      10: iconst_1
      11: istore_0
      12: iconst_2
      13: newarray       int
      15: astore_1
      16: aload_1
      17: iconst_5
      18: iconst_0
      19: iastore
      20: new           #7                  // class example/Example1$Apple
      23: dup
      24: iload_0
      25: invokespecial #8                  // Method example/Example1$Apple."<init>":(I)V
      28: astore_2
      29: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      32: ldc           #9                  // String ִ���� finally ����
      34: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      37: iconst_3
      38: istore_0
      39: new           #7                  // class example/Example1$Apple
      42: dup
      43: iload_0
      44: invokespecial #8                  // Method example/Example1$Apple."<init>":(I)V
      47: areturn
      48: astore_1
      49: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      52: ldc           #11                 // String ִ���� catch ����
      54: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      57: iconst_2
      58: istore_0
      59: new           #7                  // class example/Example1$Apple
      62: dup
      63: iload_0
      64: invokespecial #8                  // Method example/Example1$Apple."<init>":(I)V
      67: astore_2
      68: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      71: ldc           #9                  // String ִ���� finally ����
      73: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      76: iconst_3
      77: istore_0
      78: new           #7                  // class example/Example1$Apple
      81: dup
      82: iload_0
      83: invokespecial #8                  // Method example/Example1$Apple."<init>":(I)V
      86: areturn
      87: astore_3
      88: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      91: ldc           #9                  // String ִ���� finally ����
      93: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      96: iconst_3
      97: istore_0
      98: new           #7                  // class example/Example1$Apple
     101: dup
     102: iload_0
     103: invokespecial #8                  // Method example/Example1$Apple."<init>":(I)V
     106: areturn
    Exception table:
       from    to  target type
           2    29    48   Class java/lang/Exception
           2    29    87   any
          48    68    87   any
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM