天天看點

JAVA異常概述異常概述異常處理機制

異常概述

對程式員來說,需要盡可能的預知所有可能發生的錯誤情況并且做出相應處理,但是很多時候無法窮舉出所有的錯誤,例如一個隻能輸入int類型的輸入框,我們需要對double、String、Char等等類型作出判斷。JAV的異常機制可以讓程式一次性處理所有的錯誤;當程式出現意外情況時,系統會自動生成一個Exception對象通知程式,使得業務處理代碼和錯誤處理代碼分離開來;

異常處理機制

try{
    
}
catch (Exception e){
    
}
           

異常類的繼承體系

上面代碼中的Exception是所有異常類的父類,每個catch塊都是專門用于處理該異常類及其子類的異常執行個體;

當JAVA運作時環境接收到異常對象後,會依次判斷該異常對象是否是catch中定義的異常類或其子類執行個體,如果是,就調用該catch塊,否則接着往下比較;一般隻會有一個catch塊被調用;

JAVA把所有的非正常情況分為兩種:異常和錯誤,他們都繼承Throwable父類。Error錯誤一般是與虛拟機相關的錯誤,這種錯誤無法恢複或無法捕捉,通常應用程式無法處理這些錯誤;

多異常捕獲

try{

}
catch (IndexOutOfBoundsException|ArithmeticException|NumberFormatException e){

}
           

捕獲多種異常時,異常變量(上面的e)有隐式的final修飾,無法對其進行重新指派;

通路異常資訊

Java程式可以通過通路catch塊後的異常形參來獲得異常對象的相關資訊,當Java運作時決定調用某個catch塊來處理該異常對象時,會将異常對象賦給catch塊後的異常參數,程式即可通過該參數來獲得異常的相關資訊。

所有異常對象都包含了如下幾種常用方法:

getMessage():傳回該異常的較長的描述字元串。
printStackTrace():将該異常的跟蹤棧資訊輸出到标準錯誤輸出。
printStackTrace(PrintStream s):将該異常的跟蹤棧資訊輸出到指定輸出流。
getStackTrace:傳回該異常的跟蹤棧資訊。

使用finally回收資源

try中的代碼有時候會打開一些需要顯式回收的實體資源,這時候回收代碼如果寫在try裡,當try中抛出異常時回收代碼沒法執行,寫在catch裡正常運作時又沒法回收,是以JAVA提供了finally塊,finally塊總會被執行;

JAVA9的自動關閉資源的try語句

JAVA9允許try後面緊跟一對圓括号,括号中可以聲明、初始化資源,這些資源會在try中語句執行完後自動回收;

為了保證try語句能正常關閉資源,這些資源實作類必須實作AutoCloseable或Closeable接口;

Checked異常和Runtime異常體系

Java的異常被分為兩大類:Checked異常和Runtime異常(運作時異常)。所有RuntimeException類及其子類執行個體被稱為Runtime異常;不是RuntimeException類及其子類的異常執行個體則稱為Checked異常。

隻有Java語言提供了Checked異常,其他語言都沒有提供Checked異常。Java認為Checked異常都是可以被處理(修複)的異常,是以Java程式必須顯式處理Checked異常。

對于Checked異常的處理方式有兩種:

(1)目前方法明确知道如何處理該異常,程式應該使用try…catch塊來捕獲該異常,然後對應的catch塊中修補該異常。

(2)目前方法不知道如何處理這種異常,應該在定義該方法時聲明抛出該異常。

Runtime異常則更加靈活,Runtime異常無須顯式聲明抛出,如果程式需要捕捉Runtime異常,也可以使用try…catch塊來捕捉Runtime異常。

當使用throw語句自行抛出異常,如果throw語句抛出的異常是Checked異常,則該throw語句要麼處于try塊裡,顯式捕獲該異常,要麼放在一個帶throws聲明的方法中,即把該異常交給該方法的調用者處理;也就是說當出現了(不管是自行抛出的,還是系統抛出的)Checked異常,就要想辦法去處理它,不能不理會它,要麼顯式地在try…catch塊裡捕獲,處理它;要麼把它放在一個帶throws聲明的方法中,把異常交給該方法的調用者處理。

如果throw語句抛出的異常是Runtime異常,則該語句無須放在try塊裡,也無須放在帶throws聲明抛出的方法中;程式既可以顯式使用try…catch來捕獲,并處理異常,也可以完全不處理該異常,把異常交給該方法調用者處理。

使用throws聲明抛出異常

使用throws聲明抛出異常的思路是,目前方法不知道如何處理這種類型的異常,該異常應該由上一級調用者處理,如果main方法也不知道怎麼處理,也能使用throws把異常抛給JVM處理,JVM處理方法為:列印異常跟蹤棧資訊,并且中止程式運作。

抛出異常的幾種情況:

1.沒有使用try…catch捕獲異常,也沒有throws聲明,當不存在ssss.txt時,程式報錯,提示“必須對其捕獲或者聲明“;

public static void main(String args[]){
    FileInputStream fis = new FileInputStream("ssss.txt");
}
           

2.使用了try…catch捕獲異常,當不存在ssss.txt時,程式不會報錯,控制台輸出“異常”;

public static void main(String args[]){
    try{
        FileInputStream fis = new FileInputStream("ssss.txt");
    }
    catch(Exception e){
        System.out.println("異常");
    }
}
           

3.使用throws抛出異常,系統會列印異常的跟蹤棧資訊

public static void main(String args[]) throws IOException{ 
    FileInputStream fis = new FileInputStream("ssss.txt");
}
           

對于帶throws聲明的方法在進行重寫時,子類方法聲明的異常必須與父類相同或者是其子類。

抛出異常和處理異常

抛出異常指的是這部分代碼自己不處理異常,把異常丢給調用自己的上級,上級如果也不能處理就會接着上抛;處理異常指的是代碼自己處理這部分異常;

抛出異常的兩種方式

一、顯示地通過throws向上級抛出異常

抛出原因:當程式中可能出現異常,但又不想在本級代碼中處理時,這時候就會向上一級抛出異常。

抛出作用:向上級抛出異常可以通知上級,我這裡可能會出現異常,并且可以告訴上級我這裡可能出現哪些異常,需要上級處理或上級再向上上級抛出…,不管上級是否進行異常資訊處理,其都要顯示的進行(處理或向上上級抛出)。

二、隐式地抛出異常(即在沒有文法錯誤但可能出現邏輯或其他異常的地方)

在程式代碼中,當沒有文法錯誤,但可能出現邏輯或其他異常的時候(例如:在資料庫引起的異常),正常情況下程式是可以正常運作的,但當出現例外時就會報異常,這種異常很多時候我們并沒有人為顯示的去對異常進行處理,而是代碼中隐地逐層向上級抛出,最終在JDK底層進行異常處理。

PS:對于隐式抛出的異常,在需要處理異常的中間環節方法中可以直接try、catch捕捉異常并進行處理。

使用throw抛出異常

有時候,對于某種情況是否是異常,需要由應用的業務需求決定,在某些情況下是異常,有些情況下不是異常;例如下五子棋,當使用者輸入的下棋位置已經有棋子了,這時該引發異常;當該位置沒有棋子的時候,應該不引發異常。

使用者可以通過throw自己定義異常,當new出異常執行個體并且抛出後,系統中斷目前的執行流,并且開始執行catch裡面的語句;如以下代碼會輸出“異常”:

public static void main(String args[]){
    try{
        int a =0;
        throw new Exception("異常");
    }
    catch(Exception e){
        System.out.println(e.getMessage());
    }
}
           

之前處理異常的方式有兩種:

1.在出現異常的方法内捕獲并且處理異常,方法的調用者不能捕獲到這個異常;

2.抛出異常給方法的調用者去處理;

我們也可以在catch中定義throw,使得目前的方法能夠處理這個異常,方法的調用者也能捕獲到這個異常,兩者共同處理異常;

異常鍊模式

對于底層代碼的異常資訊,把其直接向上傳遞暴露給上層的使用者層是不負責任的行為,一般的做法是:程式捕獲原始異常并且儲存,然後抛出一個新的業務異常,新的異常中包含了對使用者的提示資訊,這也被稱為“異常鍊模式”。

所有的Throwable子類在構造器裡都可以接收一個cause對象作為參數,這個cause就用來表示原始異常,這樣可以把原始異常傳遞給新的異常,使得即使在目前位置建立并且抛出了新的異常,也能通過這個異常鍊追蹤到異常最初的位置。

public static void main(String args[]) throws SQLException {
    try{
        int a =0;
    }
    catch(Exception e){
        throw new SQLException(e);
    }
}
           

T