目錄
一:例外的概念與體系結構
1.1 例外的概念
1.2 例外的體系結構
1.3 例外的分類
1.編譯時例外:在程式編譯期間發生的例外
2.運行時例外(非受檢查例外):RunTimeException以及其子類對應的例外,都稱為運行時例外,
二:例外的處理
2.1 防御式編程
1. LBYL: Look Before You Leap. 在操作之前就做充分的檢查. 即:事前防御型
2. EAFP(例外處理的核心): It's Easier to Ask Forgiveness than Permission. "事后獲取原諒比事前獲取許可更容易". 也就是先操作, 遇到問題再處理. 即:事后認錯型
2.2 例外的拋出
注意:
2.3 例外的捕獲
1.例外宣告throws
throws與throw的區別?
注意:
2.try-catch捕獲并處理
注意:
3.finally(一定會執行)
2.4 例外的處理流程
【例外處理流程總結】
三:自定義例外類
? 注意事項
一:例外的概念與體系結構
1.1 例外的概念
在Java中,將程式執行程序中發生的不正常行為稱為例外,
比如:算數例外,陣列越界例外,空指標例外

1.2 例外的體系結構
例外種類繁多,為了對不同例外或者錯誤進行很好的分類管理,Java內部維護了一個例外的體系結構:

從上圖中可以看到:
1. Throwable:是例外體系的頂層類,其派生出兩個重要的子類, Error 和 Exception
2. Error:指的是Java虛擬機無法解決的嚴重問題,比如:JVM的內部錯誤、資源耗盡等,典型代表: StackOverflowError和OutOfMemoryError,一旦發生回力乏術.
3. Exception:例外產生后程式員可以通過代碼進行處理,使程式繼續執行,我們平時所說的例外就是Exception,
1.3 例外的分類
例外可能在編譯時發生,也可能在程式運行時發生,根據發生的時機不同,可以將例外分為:
1.編譯時例外:在程式編譯期間發生的例外
要么處理掉,要么宣告出來,

2.運行時例外(非受檢查例外):RunTimeException以及其子類對應的例外,都稱為運行時例外,
二:例外的處理
2.1 防御式編程
1. LBYL: Look Before You Leap. 在操作之前就做充分的檢查. 即:事前防御型
缺陷:正常流程和錯誤處理流程代碼混在一起, 代碼整體顯的比較混亂,
2. EAFP(例外處理的核心): It's Easier to Ask Forgiveness than Permission. "事后獲取原諒比事前獲取許可更容易". 也就是先操作, 遇到問題再處理. 即:事后認錯型
優勢:正常流程和錯誤流程是分離開的, 程式員更關注正常流程,代碼更清晰,容易理解代碼
在Java中,例外處理主要的5個關鍵字:throw、try、catch、final、throws,
2.2 例外的拋出
在撰寫程式時,如果程式中出現錯誤,此時就需要將錯誤的資訊告知給呼叫者,比如:引數檢測, 在Java中,可以借助throw關鍵字,拋出一個指定的例外物件,將錯誤資訊告知給呼叫者,具體語法如下:
throw new XXXException("例外產生的原因");
舉例:
public static int getData(int[] array,int index){
if(null==array){
throw new NullPointerException("getData:array為null");
}
if(index<0||index>=array.length){
throw new ArrayIndexOutOfBoundsException("getData:Index下標越界");
}
return array[index];
}
public static void main(String[] args) {
int[] arr = {1,2,3};
getData(arr,100);
//拋出例外
//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: getData:Index下標越界
getData(null,3);
//拋出例外
//Exception in thread "main" java.lang.NullPointerException: getData:array為null
}
注意:
1. throw必須寫在方法體內部 ,
2. 拋出的物件必須是Exception 或者 Exception 的子類物件,
3. 如果拋出的是 RunTimeException 或者 RunTimeException 的子類,則可以不用處理,直接交給JVM來處理,
4. 如果拋出的是編譯時例外,用戶必須處理,否則無法通過編譯,
5. 例外一旦拋出,其后的代碼就不會執行,
2.3 例外的捕獲
例外的捕獲,也就是例外的具體處理方式,主要有兩種:例外宣告throws 以及 try-catch捕獲處理,
1.例外宣告throws
處在方法宣告時引數串列之后,當方法中拋出編譯時例外,用戶不想處理該例外,此時就可以借助throws將例外拋給方法的呼叫者來處理,即當前方法不處理例外,提醒方法的呼叫者處理例外,
語法格式:
修飾符 回傳值型別 方法名(引數串列) throws 例外型別1,例外型別2...{
}
throws與throw的區別?
throws是用來拋出例外的,throws是用來宣告例外的,
注意:
1. throws必須跟在方法的引數串列之后
2. 宣告的例外必須是 Exception 或者 Exception 的子類
3. 方法內部如果拋出了多個例外,throws之后必須跟多個例外型別,之間用逗號隔開,如果拋出多個例外型別 具有父子關系,直接宣告父類即可,

4. 呼叫宣告拋出例外的方法時,呼叫者必須對該例外進行處理,或者繼續使用throws拋出,游標放在拋出例外方法上,alt + Insert 快速處理
2.try-catch捕獲并處理
throws對例外并沒有真正處理,而是將例外報告給拋出例外方法的呼叫者,由呼叫者處理,如果真正要對例外進行處理,就需要try-catch,
續2.2 例外的拋出的例子:

注意:
1. catch可以并列寫多個,try中可能會拋出多個不同的例外物件,則必須用多個catch來捕獲----即多種例外,多次捕獲,
如果多個例外的處理方式是完全相同, 也可以寫成這樣:
catch (ArrayIndexOutOfBoundsException | NullPointerException e) {
...
}
如果例外之間具有父子關系,一定是子類例外在前catch,父類例外在后catch,否則語法錯誤,
2. try中的代碼可能會拋出例外,也可能不會,
3. try塊內拋出例外位置之后的代碼將不會被執行 ,
4. 如果拋出例外型別與catch時例外型別不匹配,即例外不會被成功捕獲,也就不會被處理,繼續往外拋,直到 JVM收到后中斷程式----例外是按照型別來捕獲的,
5. 可以通過一個catch捕獲所有的例外,即多個例外,一次捕獲(不推薦)
3.finally(一定會執行)
在寫程式時,有些特定的代碼,不論程式是否發生例外,都需要執行,比如程式中打開的資源:網路連接、資料庫 連接、IO流等,在程式正常或者例外退出時,必須要對資源進進行回收,另外,因為例外會引發程式的跳轉,可能導致有些陳述句執行不到,finally就是用來解決這個問題的,
語法格式:
try{
// 可能會發生例外的代碼
}catch(例外型別 e){
// 對捕獲到的例外進行處理
}finally{
// 此處的陳述句無論是否發生例外,都會被執行到
}
// 如果沒有拋出例外,或者例外被捕獲處理了,這里的代碼也會執行

注意:finally中的代碼一定會執行的,一般在finally中進行一些資源清理的掃尾作業,

finally 執行的時機是在方法回傳之前(try 或者 catch 中如果有 return 會在這個 return 之前執行 finally), 但是如果 finally 中也存在 return 陳述句, 那么就會執行 finally 中的 return, 從而不會執行到 try 中原有的 return,一般我們不建議在 finally 中寫 return (被編譯器當做一個警告),
2.4 例外的處理流程
關于 "呼叫堆疊"
方法之間是存在相互呼叫關系的, 這種呼叫關系我們可以用 "呼叫堆疊" 來描述,在 JVM 中有一塊記憶體空間稱為 "虛擬機堆疊" 專門存盤方法之間的呼叫關系,當代碼中出現例外的時候, 我們就可以使用 e.printStackTrace(); 的方式查看出現例外代碼的呼叫堆疊,
如果本方法中沒有合適的處理例外的方式, 就會沿著呼叫堆疊向上傳遞
【例外處理流程總結】
- 程式先執行 try 中的代碼
- 如果 try 中的代碼出現例外, 就會結束 try 中的代碼, 看和 catch 中的例外型別是否匹配 ,
- 如果找到匹配的例外型別, 就會執行 catch 中的代碼 如果沒有找到匹配的例外型別, 就會將例外向上傳遞到上層呼叫者,
- 無論是否找到匹配的例外型別, finally 中的代碼都會被執行到(在該方法結束之前執行),
- 如果上層呼叫者也沒有處理的了例外, 就繼續向上傳遞.,
- 一直到 main 方法也沒有合適的代碼處理例外, 就會交給 JVM 來進行處理, 此時程式就會例外終止,
三:自定義例外類
我們在處理用戶名密碼錯誤的時候可能就需要拋出兩種例外, 我們可以基于已有的例外類進行擴展(繼承), 創建和我們業務相關的例外類,
具體方式:
1. 自定義例外類,然后繼承自Exception 或者 RunTimeException
2. 實作一個帶有String型別引數的構造方法,引數含義:出現例外的原因
注意事項
- 自定義例外通常會繼承自 Exception 或者 RuntimeException,
- 繼承自 Exception 的例外默認是受查例外 ,
- 繼承自 RuntimeException 的例外默認是非受查例外,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/352202.html
標籤:java
上一篇:Java網路編程基礎
