異常分類、解析過程和處理機制
阿新 • • 發佈:2020-11-03
一、異常
1.1 異常概念
異常 :指的是程式在執行過程中,出現的非正常的情況,最終會導致JVM的非正常停止。
在Java等面向物件的程式語言中,異常本身是一個類,產生異常就是建立異常物件並丟擲了一個異常物件。Java處理異常的方式是中斷處理。
注意:異常指的並不是語法錯誤,語法錯了,編譯不通過,不會產生位元組碼檔案,根本不能執行.
1.2 異常體系 Throwable體系: Error:嚴重錯誤Error,無法通過處理的錯誤。 Exception:表示異常,異常產生後程序員可以通過程式碼的方式糾正,使程式繼續執行,是必須要處理的。 Throwable中的常用方法: public void printStackTrace() :列印異常的詳細資訊,包含了異常的型別,異常的原因,還包括異常出現的位置,在開發和除錯階段,都得使用printStackTrace。
public String getMessage() :獲取發生異常的原因,提示給使用者的時候,就提示錯誤原因。
1.3 異常分類
我們平常說的異常就是指Exception,因為這類異常一旦出現,我們就要對程式碼進行更正,修復程式。異常分為兩類:
編譯時期異常:checked異常。在編譯時期,就會檢查,如果沒有處理異常,則編譯失敗。(如文字解析日期異常)
執行時期異常:runtime異常。在執行時期,檢查異常.在編譯時期,執行異常不會編譯器檢測(不報錯)。(如陣列下標越界異常、空指標異常)
異常產生的過程。
工具類
4.如果父類丟擲了多個異常,子類重寫父類方法時,丟擲和父類相同的異常或者是父類異常的子類或者不丟擲異常。 5.父類方法沒有丟擲異常,子類重寫父類該方法時也不可丟擲異常。此時子類產生該異常,只能捕獲處理,不能宣告丟擲。 三、自定義異常 概述 什麼是自定義異常類: 在開發中根據自己業務的異常情況來定義異常類,自定義一個業務邏輯異常: RegisterException,一個註冊異常類。 為什麼需要自定義異常類: Java中不同的異常類,分別表示著某一種具體的異常情況,那麼在開發中總是有些異常情況是SUN沒有定義好的,此時我們根據自己業務的異常情況來定義異常類。例如年齡負數問題,考試成績負數問題等等。 在上述程式碼中,發現這些異常都是JDK內部定義好的,但是實際開發中也會出現很多異常,這些異常很可能在JDK中沒有定義過,那麼如何自己定義異常。 異常類如何定義: 1. 自定義一個編譯期異常: 自定義類 並繼承於 java.lang.Exception 。 2. 自定義一個執行時期的異常類:自定義類 並繼承於 java.lang.RuntimeException 。
1.2 異常體系 Throwable體系: Error:嚴重錯誤Error,無法通過處理的錯誤。 Exception:表示異常,異常產生後程序員可以通過程式碼的方式糾正,使程式繼續執行,是必須要處理的。 Throwable中的常用方法: public void printStackTrace() :列印異常的詳細資訊,包含了異常的型別,異常的原因,還包括異常出現的位置,在開發和除錯階段,都得使用printStackTrace。
1.4 異常的產生過程解析
先執行下面的程式,程式會產生一個數組索引越界異常ArrayIndexOfBoundsException。我們通過圖解來解析下1 public class ArrayTools { 2 // 對給定的陣列通過給定的角標獲取元素。 3 public static int getElement(int[] arr, int index) { 4 int element = arr[index]; 5 return element; 6 } 7 }測試類
1 public class ExceptionDemo { 2 public static void main(String[] args) {上述程式執行過程圖解: 二、異常的處理 Java異常處理的五個關鍵字:try、catch、fifinally、throw、throws 2.1 丟擲異常throw 在編寫程式時,我們必須要考慮程式出現問題的情況。比如,在定義方法時,方法需要接受引數。那麼,當呼叫方法使用接受到的引數時,首先需要先對引數資料進行合法的判斷,資料若不合法,就應該告訴呼叫者,傳遞合法的資料進來。這時需要使用丟擲異常的方式來告訴呼叫者。在java中,提供了一個throw關鍵字,它用來丟擲一個指定的異常物件。 丟擲一個異常具體操作: 1. 建立一個異常物件。封裝一些提示資訊(資訊可以自己編寫)。 2. 需要將這個異常物件告知給呼叫者,通過關鍵字throw就可以完成。throw 異常物件,throw用在方法內,用來丟擲一個異常物件,將這個異常物件傳遞到呼叫者處,並結束當前方法的執行。3 int[] arr = { 34, 12, 67 }; 4 int num = ArrayTools.getElement(arr, 4) ; 5 System.out.println("num=" + num); 6 System.out.println("over"); 7 } 8 }
throw的使用:
1 public class ThrowDemo { 2 public static void main( String[] args){ 3 //建立一個數組 4 int[] arr = {2,4,52,2}; 5 //根據索引找對應的元素 6 int index = 4; 7 int element = getElement(arr, index ); 8 system.out.println(element) ; 9 system. out.println( "over" ); 10 } 11 /* 12 *根據索引找到陣列中對應的元素 13 */ 14 public static int getElement(int[]arr,int index){ 15 //判斷索引是否越界 16 if(index<0 || index>arr.length-1){ 17 /*判斷條件如果滿足,當執行完throw丟擲異常物件後,方法已經無法繼續運算。這時就會結束當前方法的執行,並將異常告知給呼叫者。這時就需要通過異常來解 18 決。*/ 19 throw new ArrayIndexOutOfBoundsException("陣列下標越界!"); 20 } 21 int element = arr[index]; 22 return element; 23 } 24 } 25注意:如果產生了問題,我們就會throw將問題描述類即異常進行丟擲,也就是將問題返回給該方法的呼叫者。那麼對於呼叫者來說,一種是進行捕獲處理,另一種就是繼續講問題宣告出去,使用throws宣告處理。 2.3 宣告異常throws 宣告異常:將問題標識出來,報告給呼叫者。如果方法內通過throw丟擲了編譯時異常,而沒有捕獲處理(try-catch),那麼必須通過throws進行宣告,讓呼叫者去處理。 關鍵字throws運用於方法宣告之上,用於表示當前方法不處理異常,而是提醒該方法的呼叫者來處理異常(丟擲異常)。 宣告異常格式: 修飾符 返回值型別 方法名(引數) throws 異常類名1,異常類名2…{ } 宣告異常的程式碼演示:
1 public class ThrowsDemo2 { 2 public static void main(String[ ] args) throws IOException { 3 read( "a.txt"); 4 } 5 public static void read(String path)throws FileNotFoundException,IOException{ 6 if (!path.equals( "a.txt")){//如果不是a.txt這個檔案 7 //假設 如果不是a.txt 認為該檔案不存在是一個錯誤,也就是異常throw 8 throw new FileNotFoundException( "檔案不存在"); 9 } 10 if ( ! path.equals( "b.txt" )) { 11 throw new IOException(); 12 } 13 } 14 }2.4 捕獲異常try…catch 如果在一個方法中出現異常的話,會立刻終止程式,所以我們得處理異常,有兩種方式: 1. 該方法不處理,而是宣告丟擲(throws),由該方法的呼叫者來處理。 2. 在方法中使用try-catch的語句塊來處理異常。 try-catch的方式就是捕獲異常。 捕獲異常:Java中對異常有針對性的語句進行捕獲,可以對出現的異常進行指定方式的處理。 捕獲異常語法如下:
1 try{ 2 編寫可能會出現異常的程式碼 3 }catch(異常型別 e){ 4 處理異常的程式碼 //記錄日誌/列印異常資訊/繼續丟擲異常 5 }try:該程式碼塊中編寫可能產生異常的程式碼。 catch:用來進行某種異常的捕獲,實現對捕獲到的異常進行處理。 注意:try和catch都不能單獨使用,必須連用。 演示如下:
1 public class TryCatchDemo { 2 public static void main(String[ ] args) { 3 try {//當產生異常時,必須有處理方式。要麼捕獲,要麼宣告。 4 read( "b.txt" ); 5 }catch (FileNotFoundException e) {/try中丟擲的是什麼異常,在括號中就定義什麼異常型別 6 system. out.println(e); 7 } 8 system. out.println( "over"); 9 } 10 /*這個方法中有編譯期異常*/ 11 public static void read(String path) throws FileNotFoundException { 12 if ( ! path.equals ( "a.txt")){//如果不是a.txt這個檔案 13 //假設 如果不是a.txt認為該檔案不存在是一個錯誤也就是異常throw 14 throw new FileNotFoundException( "檔案不存在"); 15 } 16 } 17 }如何獲取異常資訊: Throwable類中定義了一些檢視方法: public String getMessage() :獲取異常的描述資訊,原因(提示給使用者的時候,就提示錯誤原因。 public void printStackTrace() :列印異常的跟蹤棧資訊並輸出到控制檯,包含了異常的型別,異常的原因,還包括異常出現的位置,在開發和除錯階段,都得使用printStackTrace。 2.4 finally 程式碼塊 finally:有一些特定的程式碼無論異常是否發生,都需要執行。因為異常會引發程式跳轉,導致有些語句執行不到,而finally就是解決這個問題的,在finally程式碼塊中存放的程式碼都是一定會被執行的。 例如:當我們在try語句塊中打開了一些物理資源(磁碟檔案/網路連線/資料庫連線等),我們都得在使用完之後,最終關閉開啟的資源。 finally的語法: try...catch...finally:自身需要處理異常,最終還得關閉資源。 注意:finally不能單獨使用。 finally程式碼參考如下:
1 public class TryCatchDemo2 { 2 public static void main(String[] args) { 3 try { 4 read("a.txt"); 5 } catch (FileNotFoundException e) { 6 //抓取到的是編譯期異常 丟擲去的是執行期 7 throw new RuntimeException(e); 8 } finally { 9 System.out.println("不管程式怎樣,這裡都將會被執行。"); 10 } 11 System.out.println("over"); 12 } 13 /*當前的這個方法中 有異常 有編譯期異常 */ 14 public static void read(String path) throws FileNotFoundException { 15 if (!path.equals("a.txt")) {//如果不是 a.txt這個檔案 16 //假設 如果不是 a.txt 認為 該檔案不存在 是一個錯誤 也就是異常 throw 17 throw new FileNotFoundException("檔案不存在"); 18 } 19 } 20 }
注意:當只有在try或者catch中呼叫退出JVM的相關方法,此時fifinally才不會執行,否則fifinally永遠會執行。
2.5 異常注意事項 1.多個異常使用捕獲該如何處理: (1)多個異常分別處理。 (2)多個異常一次捕獲,多次處理。 (3)多個異常一次捕獲,一次處理。 一般我們是使用一次捕獲多次處理方式,格式如下:1 try{ 2 編寫可能會出現異常的程式碼 3 }catch(異常型別A e){ 4 當try中出現A型別異常,就用該catch來捕獲. 處理異常的程式碼 5 //記錄日誌/列印異常資訊/繼續丟擲異常 6 }catch(異常型別B e){ 7 當try中出現B型別異常,就用該catch來捕獲. 處理異常的程式碼 8 //記錄日誌/列印異常資訊/繼續丟擲異常 9 }...注意:這種異常處理方式,要求多個catch中的異常不能相同,並且若catch中的多個異常之間有子父類異常的關係,那麼子類異常要求在上面的catch處理,父類異常在下面的catch處理。 2.執行時異常被丟擲可以不處理。即不捕獲也不宣告丟擲。 3.如果fifinally有return語句,永遠返回fifinally中的結果,避免該情況
4.如果父類丟擲了多個異常,子類重寫父類方法時,丟擲和父類相同的異常或者是父類異常的子類或者不丟擲異常。 5.父類方法沒有丟擲異常,子類重寫父類該方法時也不可丟擲異常。此時子類產生該異常,只能捕獲處理,不能宣告丟擲。 三、自定義異常 概述 什麼是自定義異常類: 在開發中根據自己業務的異常情況來定義異常類,自定義一個業務邏輯異常: RegisterException,一個註冊異常類。 為什麼需要自定義異常類: Java中不同的異常類,分別表示著某一種具體的異常情況,那麼在開發中總是有些異常情況是SUN沒有定義好的,此時我們根據自己業務的異常情況來定義異常類。例如年齡負數問題,考試成績負數問題等等。 在上述程式碼中,發現這些異常都是JDK內部定義好的,但是實際開發中也會出現很多異常,這些異常很可能在JDK中沒有定義過,那麼如何自己定義異常。 異常類如何定義: 1. 自定義一個編譯期異常: 自定義類 並繼承於 java.lang.Exception 。 2. 自定義一個執行時期的異常類:自定義類 並繼承於 java.lang.RuntimeException 。