Throwable 是 Java 語言中所有錯誤與異常的超類。
Error 類及其子類:程序中無法處理的錯誤,表示運行應用程序中出現了嚴重的錯誤。
Exception 程序本身可以捕獲并且可以處理的異常。Exception 這種異常又分為兩類:運行時異常和編譯時異常。
運行時異常 都是RuntimeException類及其子類異常,如NullPointerException(空指針異常)、IndexOutOfBoundsException(下標越界異常)等,這些異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。這些異常一般是由程序邏輯錯誤引起的,程序應該從邏輯角度盡可能避免這類異常的發生。 運行時異常的特點是Java編譯器不會檢查它,也就是說,當程序中可能出現這類異常,即使沒有用try-catch語句捕獲它,也沒有用throws子句聲明拋出它,也會編譯通過。
非運行時異常 (編譯異常)是RuntimeException以外的異常,類型上都屬于Exception類及其子類。從程序語法角度講是必須進行處理的異常,如果不處理,程序就不能編譯通過。如IOException、SQLException等以及用戶自定義的Exception異常,一般情況下不自定義檢查異常。
異常需要處理的時機分為編譯時異常(也叫受控異常)也叫 CheckedException 和運行時異常(也叫非受控異常)也叫 UnCheckedException。Java認為Checked異常都是可以被處理的異常,所以Java程序必須顯式處理Checked異常。如果程序沒有處理Checked 異常,該程序在編譯時就會發生錯誤無法編譯。這體現了Java 的設計哲學:沒有完善錯誤處理的代碼根本沒有機會被執行。
對Checked異常處理方法有兩種:
● 第一種:當前方法知道如何處理該異常,則用try...catch塊來處理該異常。
● 第二種:當前方法不知道如何處理,則在定義該方法時聲明拋出該異常。
運行時異常只有當代碼在運行時才發行的異常,編譯的時候不需要try…catch。Runtime如除數是0和數組下標越界等,其產生頻繁,處理麻煩,若顯示申明或者捕獲將會對程序的可讀性和運行效率影響很大。所以由系統自動檢測并將它們交給缺省的異常處理程序。當然如果你有處理要求也可以顯示捕獲它們。
Java 的異常處理是通過 5 個關鍵詞來實現的:try、catch、throw、throws 和 finally。
一般情況下是用 try 來執行一段程序,如果出現異常,系統會拋出(throw)一個異常,這時候你可以通過它的類型來捕捉(catch)它,或最后(finally)由缺省處理器來處理;try 用來指定一塊預防所有“異常”的程序;catch 子句緊跟在 try 塊后面,用來指定你想要捕捉的“異常”的類型;throw 語句用來明確地拋出一個“異常”;throws 用來標明一個成員函數可能拋出的各種“異常”;finally 為確保一段代碼不管發生什么“異常”都被執行一段代碼;可以在一個成員函數調用的外面寫一個 try 語句,在這個成員函數內部寫另一個 try 語句保護其他代碼。每當遇到一個 try 語句,“異常”的框架就放到棧上面,直到所有的try 語句都完成。如果下一級的 try 語句沒有對某種"異常"進行處理,棧就會展開,直到遇到有處理這種"異常"的 try 語句。
會執行,在方法返回調用者前執行。Java 允許在 finally 中改變返回值的做法是不好的,因為如果存在 finally 代碼塊,try 中的 return 語句不會立馬返回調用者,而是記錄下返回值待 finally 代碼塊執行完畢之后再向調用者返回其值,然后如果在 finally 中修改了返回值,這會對程序造成很大的困擾,C#中就從語法上規定不能做這樣的事。
Error 表示系統級的錯誤和程序不必處理的異常,是恢復不是不可能但很困難的情況下的一種嚴重問題;比如內存溢出,不可能指望程序能處理這樣的情況;Exception 表示需要捕捉或者需要程序進行處理的異常,是一種設計或實現問題;也就是說,它表示如果程序運行正常,從不會發生的情況。
public int getNum() {
try {
int a = 1 / 0;
return 1;
} catch (Exception e) {
return 2;
} finally {
return 3;
}
}
分析:代碼走到第3行的時候遇到了一個MathException,這時第4行的代碼就不會執行了,代碼直接跳轉到catch語句中,走到第 6 行的時候,異常機制有一個原則:如果在catch中遇到了return或者異常等能使該函數終止的話那么有finally就必須先執行完finally代碼塊里面的代碼然后再返回值。因此代碼又跳到第8行,可惜第8行是一個return語句,那么這個時候方法就結束了,因此第6行的返回結果就無法被真正返回。因此上面返回值是3。
有如下代碼片斷:
try{
throw new ExampleB(“b”);
}catch(ExampleA e){
System.out.printfln(“ExampleA”);
}catch(Exception e){
System.out.printfln(“Exception”);
}
輸出的內容應該是:ExampleA
●java.lang.NullPointerException 空指針異常;出現原因:調用了未經初始化的對象或者是不存在的對象。
● java.lang.IndexOutOfBoundsException 數組角標越界異常,常見于操作數組對象時發生。
● java.lang.ClassNotFoundException 指定的類找不到;出現原因:類的名稱和路徑加載錯誤;通常都是程序試圖通過字符串來加載某個類時可能引發異常。
● java.lang.ClassCastException 數據類型轉換異常。
● java.lang.SQLException SQL異常,常見于操作數據庫時的 SQL 語句錯誤。
● throw:
throw 語句用在方法體內,表示拋出異常,由方法體內的語句處理。
throw是具體向外拋出異常的動作,所以它拋出的是一個異常實例,執行throw一定是拋出了某種異常。
● throws:
throws語句是用在方法聲明后面,表示如果拋出異常,由該方法的調用者來進行異常的處理。
throws主要是聲明這個方法會拋出某種類型的異常,讓它的使用者要知道需要捕獲的異常的類型。
如果你的資源實現了 AutoCloseable 接口,你可以使用這個語法。大多數的 Java 標準資源都繼承了這個接口。當你在 try 子句中打開資源,資源會在 try 代碼塊執行后或異常處理后自動關閉。
public void automaticallyCloseResource() {
File file = new File("./tmp.txt");
try (FileInputStream inputStream = new FileInputStream(file);) {
// use the inputStream to read a file
} catch (FileNotFoundException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
}
public static void simpleTryCatch() {
try {
testNPE();
} catch (Exception e) {
e.printStackTrace();
}
}
使用javap來分析這段代碼(需要先使用javac編譯)。
//javap -c Main
public static void simpleTryCatch();
Code:
0: invokestatic #3 // Method testNPE:()V
3: goto 11
6: astore_0
7: aload_0
8: invokevirtual #5 // Method java/lang/Exception.printStackTrace:()V
11: return
Exception table:
from to target type
0 3 6 Class java/lang/Exception
異常表中包含了一個或多個異常處理者(Exception Handler)的信息,這些信息包含如下
1)from 可能發生異常的起始點
2)to可能發生異常的結束點
3)target上述from和to之前發生異常后的異常處理者的位置
4)type異常處理者處理的異常的類信息