JAVA 系列——>異常(try、catch、finally、throw、throws)

異常,就是不正常的意思。

在生活中:醫生說,你的身體某個部位有異常,該部位和正常相比有點不同,該部位的功能將 受影響.
在程序中的意思就是: 異常 :指的是程序在執行過程中,出現的非正常的情況,最終會導致JVM的非正常停止。

在Java等面向對象的編程語言中,異常本身是一個,產生異常就是創建異常對象並拋出了一個異常對象。Java處 理異常的方式是中斷處理

異常指的並不是語法錯誤,語法錯了,編譯不通過,不會產生字節碼文件,根本不能運行.

異常機制其實是幫助我們找到程序中的問題,異常的根類是 java.lang.Throwable ,其下有兩個子類: java.lang.Error 與 java.lang.Exception ,平常所說的異常指 java.lang.Exception 。
在這裏插入圖片描述
Throwable體系:
Error:嚴重錯誤Error,無法通過處理的錯誤,只能事先避免,好比絕症。
Exception:表示異常,異常產生後程序員可以通過代碼的方式糾正,使程序繼續運行,是必須要處理的。好 比感冒、闌尾炎。

Throwable中的常用方法:
public void printStackTrace() :打印異常的詳細信息。 包含了異常的類型,異常的原因,還包括異常出現的位置,在開發和調試階段,都得使用printStackTrace。
public String getMessage() :獲取發生異常的原因。 提示給用戶的時候,就提示錯誤原因。
**public String toString() 😗*獲取異常的類型和異常描述信息(不用)。

出現異常,不要緊張,把異常的簡單類名,拷貝到API中去查。
在這裏插入圖片描述

異常分類

我們平常說的異常就是指Exception,因爲這類異常一旦出現,我們就要對代碼進行更正,修復程序。

異常(Exception)的分類:根據在編譯時期還是運行時期去檢查異常?
編譯時期異常:checked異常。在編譯時期,就會檢查,如果沒有處理異常,則編譯失敗。(如日期格式化異常)
運行時期異常:runtime異常。在運行時期,檢查異常.在編譯時期,運行異常不會編譯器檢測(不報錯)。(如數學異常)
在這裏插入圖片描述

異常的產生過程解析

先運行下面的程序,程序會產生一個數組索引越界異常ArrayIndexOfBoundsException。我們通過圖解來解析下 異常產生的過程。
工具類
在這裏插入圖片描述
測試類
在這裏插入圖片描述
上述程序執行過程圖解:
在這裏插入圖片描述

異常的處理

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

拋出異常throw

在編寫程序時,我們必須要考慮程序出現問題的情況。

比如,在定義方法時,方法需要接受參數。那麼,當調用方 法使用接受到的參數時,首先需要先對參數數據進行合法的判斷,數據若不合法,就應該告訴調用者,傳遞合法的 數據進來。這時需要使用拋出異常的方式來告訴調用者。

在java中,提供了一個throw關鍵字,它用來拋出一個指定的異常對象。

那麼,拋出一個異常具體如何操作呢?

  1. 創建一個異常對象。封裝一些提示信息(信息可以自己編寫)。
  2. 需要將這個異常對象告知給調用者。怎麼告知呢?怎麼將這個異常對象傳遞到調用者處呢?通過關鍵字throw 就可以完成。throw 異常對象。

throw用在方法內,用來拋出一個異常對象,將這個異常對象傳遞到調用者處,並結束當前方法的執行。

使用格式

throw new 異常類名(參數);

例如:

throw new NullPointerException("要訪問的arr數組不存在"); 
throw new ArrayIndexOutOfBoundsException("該索引在數組中不存在,已超出範圍");

學習完拋出異常的格式後,我們通過下面程序演示下throw的使用。

  public static void main(String[] args) {
        //創建一個數組
        int[] arr = {2, 4, 52, 2};
        //根據索引找對應的元素
        int index = 4;
        int element = getElement(arr, index);
        System.out.println(element);
        System.out.println("over");
    }

    /**
     * 根據 索引找到數組中對應的元素
     */
    public static int getElement(int[] arr, int index) {
        //判斷 索引是否越界
        if (index < 0 || index > arr.length-1){
            /*判斷條件如果滿足,當執行完throw拋出異常對象後,方法已經無法繼續運算。
             這時就會結束當前方法的執行,並將異常告知給調用者。這時就需要通過異常來解決。 */
            throw new ArrayIndexOutOfBoundsException("哥們,角標越界了~~~");
        }
        int element = arr[index];
        return element;
    }

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

Objects非空判斷

還記得我們學習過一個類Objects嗎,曾經提到過它由一些靜態的實用方法組成,這些方法是null-save(空指針安 全的)或null-tolerant(容忍空指針的),那麼在它的源碼中,對對象爲null的值進行了拋出異常操作。

public static <T> T requireNonNull(T obj) :查看指定引用對象不是null

查看源碼發現這裏對爲null的進行了拋出異常操作:

public static <T> T requireNonNull(T obj) {
 if (obj == null) 
    throw new NullPointerException(); 
 return obj; 
}

聲明異常throws

聲明異常:將問題標識出來,報告給調用者。如果方法內通過throw拋出了編譯時異常,而沒有捕獲處理(稍後講 解該方式),那麼必須通過throws進行聲明,讓調用者去處理。

關鍵字throws運用於方法聲明之上,用於表示當前方法不處理異常,而是提醒該方法的調用者來處理異常(拋出異常)

聲明異常格式

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

聲明異常的代碼演示:
在這裏插入圖片描述
throws用於進行異常類的聲明,若該方法可能有多種異常情況產生,那麼在throws後面可以寫多個異常類,用逗 號隔開。
在這裏插入圖片描述

捕獲異常try…catch

如果異常出現的話,會立刻終止程序,所以我們得處理異常:

  1. 該方法不處理,而是聲明拋出,由該方法的調用者來處理(throws)。
  2. 在方法中使用try-catch的語句塊來處理異常。

try-catch的方式就是捕獲異常。
捕獲異常:Java中對異常有針對性的語句進行捕獲,可以對出現的異常進行指定方式的處理。

捕獲異常語法如下:
在這裏插入圖片描述
try:該代碼塊中編寫可能產生異常的代碼
catch:用來進行某種異常的捕獲,實現對捕獲到的異常進行處理
注意:try和catch都不能單獨使用,必須連用。

演示如下:
在這裏插入圖片描述
如何獲取異常信息:
Throwable類中定義了一些查看方法:
在這裏插入圖片描述
包含了異常的類型,異常的原因,還包括異常出現的位置,在開發和調試階段,都得使用printStackTrace。

finally 代碼塊

finally:有一些特定的代碼無論異常是否發生,都需要執行。另外,因爲異常會引發程序跳轉,導致有些語句執行 不到。
而finally就是解決這個問題的,在finally代碼塊中存放的代碼都是一定會被執行的。

什麼時候的代碼必須最終執行?
當我們在try語句塊中打開了一些物理資源(磁盤文件/網絡連接/數據庫連接等),我們都得在使用完之後,最終關閉打開 的資源。

finally的語法:
try…catch…finally:自身需要處理異常,最終還得關閉資源。
注意:finally不能單獨使用。

比如在我們之後學習的IO流中,當打開了一個關聯文件的資源,最後程序不管結果如何,都需要把這個資源關閉掉。
finally代碼參考如下:

  public static void main(String[] args) {
        try {
            read("a.txt");
        } catch (FileNotFoundException e) {
            //抓取到的是編譯期異常 拋出去的是運行期
            throw new RuntimeException(e);
        } finally {
            System.out.println("不管程序怎樣,這裏都將會被執行。");
        }
        System.out.println("over");
    }

    /*** 我們 當前的這個方法中 有異常 有編譯期異常 */
    public static void read(String path) throws FileNotFoundException {
        if (!path.equals("a.txt")) {
            //如果不是 a.txt這個文件
            // 我假設 如果不是 a.txt 認爲 該文件不存在 是一個錯誤 也就是異常
            throw throw new FileNotFoundException("文件不存在");
        }
    }

當只有在try或者catch中調用退出JVM的相關方法,此時finally纔不會執行,否則finally永遠會執行。

異常注意事項

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

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

一般我們是使用一次捕獲多次處理方式,格式如下:

在這裏插入圖片描述
注意:這種異常處理方式,要求多個catch中的異常不能相同,並且若catch中的多個異常之間有子父類異 常的關係,那麼子類異常要求在上面的catch處理,父類異常在下面的catch處理。

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

自定義異常

爲什麼需要自定義異常類:
我們說了Java中不同的異常類,分別表示着某一種具體的異常情況,那麼在開發中總是有些異常情況是SUN沒有定義 好的,此時我們根據自己業務的異常情況來定義異常類。例如年齡負數問題,考試成績負數問題等等。
在上述代碼中,發現這些異常都是JDK內部定義好的,但是實際開發中也會出現很多異常,這些異常很可能在JDK中 沒有定義過,例如年齡負數問題,考試成績負數問題.那麼能不能自己定義異常呢?

什麼是自定義異常類:
在開發中根據自己業務的異常情況來定義異常類.
自定義一個業務邏輯異常: RegisterException。一個註冊異常類。

異常類如何定義:

  1. 自定義一個編譯期異常: 自定義類 並繼承於 java.lang.Exception 。
  2. 自定義一個運行時期的異常類:自定義類 並繼承於 java.lang.RuntimeException 。

自定義異常的練習

要求:我們模擬註冊操作,如果用戶名已存在,則拋出異常並提示:親,該用戶名已經被註冊。
首先定義一個登陸異常類RegisterException:
在這裏插入圖片描述
模擬登陸操作,使用數組模擬數據庫中存儲的數據,並提供當前註冊賬號是否存在方法用於判斷。

  // 模擬數據庫中已存在賬號
        private static String[] names = {"bill", "hill", "jill"};
        public static void main (String[]args)
        {
            //調用方法
            try {
                // 可能出現異常的代碼
                checkUsername("bill");
                System.out.println("註冊成功");
                //如果沒有異常就是註冊成功
            } catch (RegisterException e) {
                //處理異常
                e.printStackTrace();
            }
        }

        //判斷當前註冊賬號是否存在
        //因爲是編譯期異常,又想調用者去處理 所以聲明該異常
        public static boolean checkUsername (String uname) throws RegisterException {
            for (String name : names) {
                if (name.equals(uname)) {//如果名字在這裏面 就拋出登陸異常
                    throw new RegisterException("親" + name + "已經被註冊了!");
                }
            }
            return true;
        }

結果:
在這裏插入圖片描述

發佈了65 篇原創文章 · 獲贊 45 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章