1. 程式人生 > 其它 >【Java基礎進階筆記】- Day05 - 第二章 異常的處理

【Java基礎進階筆記】- Day05 - 第二章 異常的處理

技術標籤:【Java基礎進階筆記】Javathrowthrows

Java基礎進階筆記 - Day05 - 第二章 異常的處理

Java基礎進階筆記 - Day05 - 第二章 異常的處理

系統:Win10
JDK:1.8.0_121
IDE:IntelliJ IDEA 2017.3.7

Java異常處理的五個關鍵字:try、catch、finally、throw、throws

2.1 丟擲異常throw

在編寫程式時,我們必須要考慮程式出現問題的情況。比如,在定義方法時,方法需要接受引數。那麼,當呼叫方法使用接受到的引數時,首先需要先對引數資料進行合法的判斷,資料若不合法,就應該告訴呼叫者,傳遞合法的資料進來。這時需要使用丟擲異常的方式來告訴呼叫者
在java中,提供了一個throw關鍵字,它用來丟擲一個指定的異常物件。那麼,丟擲一個異常具體如何操作呢?

  1. 建立一個異常物件,封賬一些提示資訊(資訊可以自己編寫)
  2. 需要將這個異常物件告知給呼叫者。怎麼告知?怎麼將這個異常物件傳遞到呼叫者處?通過關鍵字throw就可以完成。throw異常物件

throw用在方法內,用來丟擲一個異常物件,將這個異常物件傳遞到呼叫者處,並結束當前方法的執行

使用格式:

throw new 異常類名(引數);

例如:

throw new NullPointerException("訪問的東西不存在!");
throw new ArrayIndexOutOfBoundsException("訪問超出陣列範圍了!");

學習完丟擲異常的格式後,我們通過下面程式瞭解下throw的使用

public class ThrowDemo01 {
    public static void main(String[] args) {
        // 建立一個數組
        int[] arr = {1, 3, 5
, 7}; // 根據索引找到對應的元素 int index = 4; int e = getElement(arr, index); System.out.println(e); System.out.println("程式碼結束!"); } // 根據索引找到陣列中對應的元素 private static int getElement(int[] arr, int index) { // 判斷索引是否越界 if (index < 0 || index > arr.length - 1) { /* 判斷條件滿足,當執行完throw丟擲異常後,方法無法繼續運算 這時就會結束當前方法的執行,並將異常告知呼叫者。 */ throw new ArrayIndexOutOfBoundsException("索引越界異常了!!!"); } int e = arr[index]; return e; } }

執行結果:
在這裡插入圖片描述

注意:如果產生了問題,我們就會throw將問題描述類異常進行丟擲,也就是將問題返回給該方法的呼叫者
那麼對於呼叫者來說,該怎麼處理?一種是進行捕獲處理,另一種就是繼續將問題宣告出去,使用throws宣告處理

2.2 Objects非空判斷

我們之前瞭解過一個Objects類,曾經提到過它由一些靜態方法組成,這些方法是null-save(空指標安全的)或null-tolerant(容忍空指標的),那麼在它的原始碼中,對物件為null的值進行了丟擲異常操作

  • public static T requireNonNull(T obj):檢視指定引用物件不是null
    檢視原始碼發現這裡對是null的值進行了丟擲異常:
public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}

2.3 宣告異常throws

宣告異常:將問題標識出來,報告給呼叫者。如果方法內通過throw丟擲編譯時異常,而沒有捕獲處理(稍後講解該方式),那麼必須通過throws進行宣告,讓呼叫者去處理
關鍵字throws運用於方法宣告之上,用於表示當前方法不處理異常,而是提醒該方法的呼叫者來處理異常(丟擲異常)
宣告異常格式:

修飾符 返回值型別 方法名(引數) throws 異常類名1, 異常類名2, ... {
    // ...
}

宣告異常的程式碼演示

public class ThrowsDemo01 {
    public static void main(String[] args) throws FileNotFoundException{
        // read("C:\\a.txt");
        read("C:\\b.txt");
        System.out.println("程式碼結束!");
    }

    /*
     如果定義功能時有問題發生,需要報告給呼叫者。
     可以通過在方法上使用throws關鍵字進行宣告
     */
    private static void read(String path) throws FileNotFoundException{
        if (path.indexOf("a.txt") == -1) {
            // 如果不是 C:\a.txt 則認為該檔案不存在
            throw new FileNotFoundException("該檔案不存在!");
        }
    }
}

執行結果:
在這裡插入圖片描述

throws用於進行異常類的宣告,若該方法可能有多種異常情況產生,那麼可以在throws後面寫多個異常類,用逗號隔開

public class ThrowsDemo02 {
    public static void main(String[] args) throws FileNotFoundException, IOException {
        // read("C:\\a.txt");
        // read("C:\\b.txt");
        read("D\\a.txt");
        System.out.println("程式碼結束!");
    }

    /*
     如果定義功能時有問題發生,需要報告給呼叫者。
     可以通過在方法上使用throws關鍵字進行宣告
     */
    private static void read(String path) throws FileNotFoundException, IOException {
        if (path.indexOf("a.txt") == -1) {
            // 如果不是 C:\a.txt 則認為該檔案不存在
            throw new FileNotFoundException("該檔案不存在!");
        }
        if (path.indexOf("C:\\") == -1) {
            throw new IOException("發生了讀寫異常!!!");
        }
    }
}

執行結果:
在這裡插入圖片描述

throw和throws的區別:
throw:丟擲一個異常,具體的一個動作,就是這裡有一個異常的意思
throws:宣告異常,就是表示我這個方法可能有異常,你們用的時候小心點,記得處理異常。呼叫者的可以在自己方法上新增宣告,繼續提醒,最終交給JVM處理,或者使用try…catch捕獲異常進行處理

2.4 捕獲異常try…catch

如果異常出現而我們不處理的話,會立刻終止程式,所以我們需要處理異常

  1. 在方法內不處理,而是宣告丟擲,由該方法的呼叫者來處理(throws)
  2. 在方法中使用try-catch的語句來處理異常

try-catch的方式就是捕獲異常

  • 捕獲異常:Java中對異常有針對性的語句進行捕獲,可以對出現的異常進行指定方式的處理
    捕獲異常語句語法如下
try{
    // 編寫可能會出現異常的程式碼
} catch (異常型別 e) {
    // 處理異常的程式碼
    // 記錄日誌/列印異常資訊/繼續丟擲異常
}

try:該程式碼塊中編寫可能出現異常的程式碼
catch:用來進行某種異常的捕獲,實現對捕獲到的異常進行處理

注意:try和catch都不能單獨使用,必須連用

程式碼演示:

public class TryCatchDemo01 {
    public static void main(String[] args) {
        try { // 當產生異常的時候,必須有處理方式。要麼捕獲,要麼宣告
            read("C:\\b.txt");
        } catch (FileNotFoundException e) {
            System.out.println(e);
        }
        System.out.println("程式碼結束!");
    }

    /*
     我們這個方法有編譯期異常
     */
    private static void read(String path) throws FileNotFoundException {
        if (path.indexOf("a.txt") == -1) {
            // 如果不是 C:\a.txt 則認為該檔案不存在
            throw new FileNotFoundException("該檔案不存在!");
        }
    }
}

執行結果:
在這裡插入圖片描述

小知識:像前面的ArrayIndexOutOfBoundsException屬於執行期異常,可以不作throws宣告,直接丟擲。像這裡的FileNotFoundException屬於編譯期異常,要麼宣告,要麼捕獲,一定要處理的,不然不能編譯

如何獲取異常資訊
Throwable類中定義了一些檢視方法:

  • public String getMessage():獲取異常的描述資訊,原因(提示使用者的時候,只顯示錯誤原因)
  • public String toString():獲取異常的型別和異常描述資訊
  • public void printStackTrace():列印異常的跟蹤棧資訊並輸出到控制檯,包含了異常的型別、異常的原因、還有異常出現的位置。在開發和除錯階段,都得使用printStackTrace

2.5 finally程式碼塊

finally:有一些特定的程式碼無論異常是否發生,都需要執行。另外,因為異常會引發程式跳轉,導致有些語句執行不到。而finally就是解決這個問題的,在finally程式碼塊中存放的程式碼都是一定會被執行的
什麼時候的程式碼必須最終執行?
當我們在try語句塊中開啟一些物理資源(磁碟檔案/網路連線/資料庫連線等),我們在最終使用完之後,都得關閉開啟的資源
finally的語法:
try…catch…finally:自身需要處理異常,最終還得關閉資源

注意:finally不能單獨使用

比如我們接下來學習的IO流中,當開啟一個關聯檔案的資源,最後程式不管結果如何,都需要把這個資源關閉掉
finally程式碼參考如下:

public class TryCatchDemo02 {
    public static void main(String[] args) {
        try { // 當產生異常的時候,必須有處理方式。要麼捕獲,要麼宣告
            read("C:\\b.txt");
        } catch (FileNotFoundException e) {
            System.out.println(e);
        } finally {
            System.out.println("釋放資源!");
        }
        System.out.println("程式碼結束!");
    }

    /*
     我們這個方法有編譯期一異常
     */
    private static void read(String path) throws FileNotFoundException {
        if (path.indexOf("a.txt") == -1) {
            // 如果不是 C:\a.txt 則認為該檔案不存在
            throw new FileNotFoundException("該檔案不存在!");
        }
    }
}

執行結果:
在這裡插入圖片描述

小知識:只有當try或者catch中呼叫或者退出JVM的相關方法時,finally不會執行。其他情況下finally永遠都會執行

2.6 異常注意事項

多個異常使用捕獲該如何處理?

  1. 多個異常分別處理
  2. 多個異常一次捕獲,多次處理
  3. 多個異常一次捕獲,一次處理

多個異常分別處理的格式如下:

try {
    // 可能會出現異常的程式碼塊1
} catch(異常型別A e) {
    // 處理異常程式碼1
}
try {
    // 可能會出現異常的程式碼塊2
} catch(異常型別B e) {
    // 處理異常程式碼2
}

多個異常一次捕獲,多次處理:

try {
    // 可能會出現異常的程式碼塊
} catch(異常型別A e) {
    // 處理異常程式碼1
} catch(異常型別B e) {
    // 處理異常程式碼2
}

多個異常一次捕獲,一次處理:

try {
    // 可能會出現異常的程式碼塊
} catch(異常型別A e) { // 這裡的異常型別是所有可能出現異常的父類
    // 處理異常程式碼
}

注意:多個異常一次捕獲,多次處理的方式,要求多個catch中的異常不能相同,並且若catch中的多個異常之間有子父類異常的關係,那麼子類異常要求在上面的catch處理,父類異常在下面的catch處理

  • 執行時異常被丟擲可以不處理,既不捕獲也不宣告丟擲
  • 如果finally有return語句,永遠返回finally中的結果,避免該情況
  • 如果父類丟擲了多個異常,子類重寫父類方法時,丟擲和父類相同的異常或者是父類異常的子類或者不丟擲異常
  • 父類方法沒有丟擲異常,子類重寫父類該方法時也不可丟擲異常。此時子類產生異常,只能捕獲處理,不能宣告丟擲