更新時間:2022-08-19 09:50:57 來源:動力節(jié)點 瀏覽1407次
實際代碼
try
{
//就算這里return了,也會調(diào)用finally語句,如果finally中也有return,就會抑制這個return。
}
catch (Exception e)
{
}
finally
{
}
類型
異常拋出機(jī)制
顯式拋出:由用戶程序?qū)懘a進(jìn)行拋出,必須顯式捕獲。 通常是Exception。
隱式拋出:由Java虛擬機(jī)的安全檢查進(jìn)行拋出,比如數(shù)組越界檢查、除以0錯誤等等。不用用戶程序捕獲。通常是RunTimeError或者Error
異常捕獲機(jī)制
首先JVM為每一個方法生成一個異常表。包括{監(jiān)控起始語句 監(jiān)控終止語句 異常類型}
public static void main(String[] args) {
try {
mayThrowException();
} catch (Exception e) {
e.printStackTrace();
}
}
// 對應(yīng)的 Java 字節(jié)碼
public static void main(java.lang.String[]);
Code:
0: invokestatic mayThrowException:()V
3: goto 11
6: astore_1
7: aload_1
8: invokevirtual java.lang.Exception.printStackTrace
11: return
Exception table: // 異常表條目
from to target type
0 3 6 Class java/lang/Exception
12345678910111213141516171819
其中的from和to分別對應(yīng)著監(jiān)控的字節(jié)碼的代碼。類型就是捕獲的Exception類型。
把finally中的代碼“內(nèi)聯(lián)”到try和catch中各一份,或者只在catch中放一份,在try中放入跳轉(zhuǎn)指令。
然后如果Exception就直接進(jìn)入catch語句,如果遇見Error,直接執(zhí)行了finally。
public class Foo {
private int tryBlock;
private int catchBlock;
private int finallyBlock;
private int methodExit;
public void test() {
try {
tryBlock = 0;
} catch (Exception e) {
catchBlock = 1;
} finally {
finallyBlock = 2;
}
methodExit = 3;
}
}
$ javap -c Foo
...
public void test();
Code:
0: aload_0
1: iconst_0
2: putfield #20 // Field tryBlock:I
5: goto 30
8: astore_1
9: aload_0
10: iconst_1
11: putfield #22 // Field catchBlock:I
14: aload_0
15: iconst_2
16: putfield #24 // Field finallyBlock:I
19: goto 35
22: astore_2
23: aload_0
24: iconst_2
25: putfield #24 // Field finallyBlock:I
28: aload_2
29: athrow
30: aload_0
31: iconst_2
32: putfield #24 // Field finallyBlock:I
35: aload_0
36: iconst_3
37: putfield #26 // Field methodExit:I
40: return
Exception table:
from to target type
0 5 8 Class java/lang/Exception
0 14 22 any
...
可以看到,編譯結(jié)果包含三份 finally 代碼塊。其中,前兩份分別位于 try 代碼塊和 catch 代碼塊的正常執(zhí)行路徑出口。最后一份則作為異常處理器,監(jiān)控 try 代碼塊以及 catch 代碼塊。它將捕獲 try 代碼塊觸發(fā)的、未被 catch 代碼塊捕獲的異常,以及 catch 代碼塊觸發(fā)的異常。
背景
finally中的語句也有可能拋出錯誤,但是關(guān)閉資源這個錯誤的根本原因,可能式第一個被拋出的錯誤引起的,而被拋出的錯誤確實finally語句中的錯誤,從而導(dǎo)致了根本錯誤被supress。
代碼層面實現(xiàn)
所以為了得到第一個錯誤,加入了Surpress機(jī)制,反映到代碼層面就是try-with-resource語句。使用try-with-resource語句,會自動關(guān)閉資源,從而避免了內(nèi)存泄漏的問題。另外使用try-with-resource語句,會抑制finally語句中的拋出的錯誤。可以使用addSupress和getSupress獲取全部的Exception。
實例
@Test
public void testJdk7TryWith() {
try(InputStream inputStream = new FileInputStream(new File("test"))) {
} catch(Exception e) {
e.printStackTrace();
}
}
/*
*
* 由于第一個異常可能是根本原因,那么怎么進(jìn)行捕獲呢?
* */
public static void main(String[] args) throws Exception {
InputStream in = null;
Exception ex = null;
try {
in = new FileInputStream(new File("tes"));
} catch (FileNotFoundException e) {
ex = e;
throw e;
} finally {
try {
in.close();
} catch (IOException e) {
if (ex == null) {
System.out.println("有這個文件就不拋出了");
throw e;
}
} catch (NullPointerException e) { // 因為in會出現(xiàn)空指針,抑制第一個文件的拋出
if (ex == null) {
System.out.println("有這個文件就不拋出了");
}
}
}
}
最后注意
使用鎖,不能使用try-with語句,必須顯式的調(diào)用unlock方法。代碼如下
@Test
public void testLock() {
Lock myLock = new ReentrantLock();
try {
myLock.lock();
} catch (Exception e) {
throw e;
} finally {
myLock.unlock();
}
}
以上就是關(guān)于“Java異常處理機(jī)制原理”的介紹,大家如果想了解更多相關(guān)知識,可以關(guān)注一下動力節(jié)點的Java入門視頻教程,里面有更豐富的知識等著大家去學(xué)習(xí),希望對大家能夠有所幫助。
相關(guān)閱讀
初級 202925
初級 203221
初級 202629
初級 203743