一、概述
Java中, 所以的異常都繼承自java.lang.Throwable。

Throwable: Throwable是Java中所有錯誤(error)和異常(Exception)的父類。 錯誤和異常的區(qū)別是異??梢员粦贸绦蛱幚?, 而錯誤無法被處理。Error: Error是無法處理的錯誤, 表示程序運行中出現(xiàn)比較嚴重的問題。大多數(shù)Error和代碼編寫者無關, 表示代碼運行時JVM(Java虛擬機)出現(xiàn)的問題。Exception: Exception是程序自身可以處理的異常,Exception有一個重要的子類RuntimeException, 代表運行時異常。這些異常時非檢查異常, 應用程序中可以處理,也可以不處理,一般是由程序錯誤邏輯引起的。除過非檢出異常, 其他的異常都是檢查異常, 檢查異常如果不處理, 程序就無法編譯通過。
二、異常(Exception)
1、檢查異常(CheckedException)
程序運行中,很容易出現(xiàn)的、情理可容的異常。除了RuntimeException及其子類外, 其他的都是檢出異常。檢出異常必須被處理, Java編譯器會檢查這種異常, 當遇到這種異常時,要么使用try/catch捕獲它, 要么使用throw拋出它。
常見的檢查異常:
| 序號 | 異常名稱 | 異常描述 |
|---|---|---|
| 1 | NoSuchFieldException | 表示該類沒有指定名稱拋出來的異常 |
| 2 | NoSuchMethodException | 表示該類沒有指定方法拋出來的異常 |
| 3 | IllegalAccessException | 不允許訪問某個類的異常 |
| 4 | ClassNotFoundException | 類沒有找到拋出異常 |
| 5 | IOException | IO錯誤 |
2、非檢查異常 (UnCheckedException)
包括運行時異常RuntimeExcption和Error以及其子類,表示編譯器不會檢查程序是否對其做了處理, 出現(xiàn)運行時異常時,表示程序出現(xiàn)了錯誤, 需要找出異常并修正它。
| 序號 | 異常名稱 | 異常描述 |
|---|---|---|
| 1 | ArrayIndexOutOfBoundsException | 數(shù)組越界異常 |
| 2 | NullPointerException | 空指針異常 |
| 3 | IllegalArgumentException | 非法參數(shù)異常 |
| 4 | NegativeArraySizeException | 數(shù)組長度為負異常 |
| 5 | IllegalStateException | 非法狀態(tài)異常 |
| 6 | ClassCastException | 類型轉換異常 |
三、異常處理
1、異常處理的關鍵字
-
throw: 在方法內(nèi)部, 代表拋出這個異常。 -
thorws: 在方法的聲明中, 聲明程序可能會拋出異常, 由方法的調(diào)用者處理。 -
try/catch: 代表捕獲異常。 -
finally: 無論是否發(fā)生異常, 都會經(jīng)過finally包含的語句在返回。
2、try-with-resources
Java中很多類庫都需要在使用完成或異常發(fā)生時關閉資源, 比如Stream、Connection等等, 傳統(tǒng)的處理方式:
// 打開資源
Connection conn = //
try{
// 使用資源
}catch(Exception e){
// 處理異常
}finally{
// 判斷資源是否被關閉, 如果沒有被關閉,則主動關閉資源
if(conn != null){
// 關閉資源也可能拋出異常, 需要注意
conn.close();
}
}
凡是繼承自java.io.Closeable 和 java.io.AutoCloseable的子類都可以使用try-with-resources方式進行關閉資源:
try(Connection conn = //){ // 打開資源并且在代碼執(zhí)行結束的時候,無論是否發(fā)生異常, 主動關閉資源
// 使用資源
}catch{
// 處理異常
}
3、異常處理流程
Q:如果在try/catch中包含中包含return語句, finally中的代碼是否會執(zhí)行?
W: 一定會執(zhí)行,finally語句中的代碼在return前先執(zhí)行然后再return。
Q: 如果try/catch和finally中同時包含return語句會返回那一個?
W: 返回finally語句中返回的內(nèi)容。finally中包含return語句時, 會使try/catch中的return失效, 最終返回finally中返回的內(nèi)容.
public class UserClient2 {
public static void main(String[] args) {
System.out.println(test());
}
public static String test(){
try{
throw new Exception("-1");
// return "1";
}catch (Exception e){
return "2";
}finally {
return "3";
}
}
}
// Output
// 無論是否拋出異常, 返回的都是3。
Q: finally中包含對try/catch返回內(nèi)容的更新操作, 返回值時try/catch返回內(nèi)容, 還是finally更新后的內(nèi)容。
W: 如果返回的內(nèi)容時基本類型,則返回的是try/catch返回的值,如果返回的是引用類型, 則返回的是finally語句更新后的值。
int i = 0;
try{
i ++ ;
System.out.println(i);
return i; // 1
}catch(Exception e){
i ++; // 1
System.out.println(i);
}finally{
i++; // 2
System.out.println(i);
}
// Output
// 1
// 2
// 最終返回的是1
可以看到,最終返回的是1, 是因為return時,會先執(zhí)行return前的代碼,然后暫存return的返回值, 再執(zhí)行finally的代碼,最后通過return返回之前保存的內(nèi)容。所以這里返回的是1,而不是2, 但是對于下面這個例子,則不一樣:
List<Integer> valueList = new ArrayList();
try{
valueList.add(1);
System.out.println(valueList);
return valueList;
}catch(Exception e){
valueList.add(2);
System.out.println(valueList);
}finally{
valueList.add(3);
System.out.println(valueList);
}
// Output
// {1,}
// {1,3}
// 最終輸出是{1,3}
最終的輸出是{1,3}, 主要是因為返回的數(shù)據(jù)類型, 當返回的是基本類型時,暫存的內(nèi)容不會改變, 但是返回的是引用類型時,引用類型存的不是變量本身, 而是對變量的引用, 所以當finllay改變了變量的內(nèi)容時,最終返回結果也會被改變。
總結:
1、 finally的內(nèi)容一定會被執(zhí)行。
2、 當try/catch中包含return時, finally的代碼也會被執(zhí)行。return的時候需要注意返回的值類型, 否則返回值會受到影響。
3、 finally中包含return 時, 會直接返回finaly中的值, 導致try/catch中的return失效。