結論
結論:不一定,存在兩種可能的情況。第一種,調用了 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 語句塊。
原理
通過分析后面的反匯編代碼,我們可以看出來:
- finally 基本都是要執行的,除非暴力的 System.exit 或者線程提前終結了。
- catch 的實現方法是異常表。多個 try...catch,嵌套的 try...catch 共用一個異常表,不同方法不共用異常表。這個你可以檢驗一下。
- try 即使 return,finally 都還執行的原因,是 java 在編譯的時候,在 try 語句塊的 return 之前插入代碼。而且,return 的內容可以被 finally 的 return 覆蓋。
- 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
}
