1. 程式人生 > >Java中的異常及其用法

Java中的異常及其用法

本文主要介紹異常的概念和異常的兩種處理方式。

目錄

異常

異常概念

異常分類

異常處理

自定義異常 

概念

用法

 總結

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

異常

異常概念

         異常 :指的是程式在執行過程中,出現的非正常的情況,最終會導致JVM(Java虛擬機器)的非正常停止。
         在Java中,異常本身就是一個類,產生異常就是建立異常物件並丟擲了一個異常物件。Java處理異常就是中斷處理,程式不能繼續跑下去。
注意

:異常指的並不是語法錯誤,語法錯了,編譯不通過,不會產生位元組碼檔案,根本不能執行。

異常分類

異常的根類是java.lang.Throwable,其下有兩個子類:java.lang.Error和java.lang.Exception。平常指的異常是Exception。

Throwable體系:

  • Error:嚴重錯誤Error,無法通過處理的錯誤,只能事先避免,好比絕症。

  • Exception:表示異常,異常產生後程序員可以通過程式碼的方式糾正,使程式繼續執行,是必須要處理的。好比感冒、闌尾炎。

Throwable中的常用方法:

  • public void printStackTrace()

    :列印異常的詳細資訊。

    包含了異常的型別,異常的原因,還包括異常出現的位置,在開發和除錯階段,都得使用printStackTrace。

  • public String getMessage():獲取發生異常的原因。

    提示給使用者的時候,就提示錯誤原因。

  • public String toString():獲取異常的型別和異常描述資訊(不用)。

 異常(Exception)分類:

  • 編譯時期異常:checked異常。在編譯時期,就會檢查,如果沒有處理異常,則編譯失敗。(如日期格式化異常)

  • 執行時期異常:runtime異常。在執行時期,檢查異常.在編譯時期,執行異常不會編譯器檢測(不報錯)。(如數學異常)

注意: 當出現異常的時候,JVM會把異常的內容、原因、位置列印到控制檯,當不知道異常意思或者不知道如何處理的時候,可以把異常類名copy下來拿到API中查。(例如:java.lang.ArrayIndexOutofBoundsException-----陣列越界異常)

異常處理

丟擲異常throw

在java中,提供了一個throw關鍵字,它用來丟擲一個指定的異常物件。用法如下:

  1. 建立一個異常物件。封裝一些提示資訊(資訊可以自己編寫)。

  2. 需要將這個異常物件告知給呼叫者。通過關鍵字throw就可以完成。

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

理解:用throw就是不需要JVM來判斷異常情況,這個異常是我們自己指定的,呼叫者自己編寫異常資訊內容並告訴JVM虛擬機器出現了什麼異常,JVM只需要負責把異常資訊列印到控制檯就可以。 

 使用格式:
          throw new 異常類名(引數);
          throw new ArrayIndexOutOfBoundsException("陣列索引越界異常,該索引在陣列中不存在,已超出範圍");
例項:

public class ThrowDemo {
    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宣告處理

異常處理方式一

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

throws關鍵字:異常處理的第一種方式,交給別人處理
作用:當方法內部丟擲異常物件的時候,那麼我們就必須處理這個異常物件
          可以使用throws關鍵字來處理異常物件,會把異常物件宣告丟擲給方法的呼叫者處理(自己不處理,給別人處理),最終交給JVM處理--->中斷處理
使用格式:

修飾符  返回值型別 方法名(引數列表)  throws AAAException,BBBException...{
        throw new  AAAException("產生原因");
        throw new  AAAException("產生原因");
        ...
}


 注意事項:1. throws關鍵字必須寫在方法宣告處
             2. throws關鍵字後邊宣告的異常必須是Exception或者是Exception的子類
             3. 方法內部如果丟擲了多個異常物件,那麼throws後邊必須也宣告多個異常, 如果丟擲的多個異常物件有子父類關係,我們就必須的處理宣告的異常
             4. 呼叫了一個宣告丟擲異常的方法,我們就必須的處理宣告的異常, 要麼繼續使用throws宣告丟擲,交給方法的呼叫者處理,最終交給JVM;要麼try...catch自己處理異常

理解:說白了第一種異常處理方式就是通過JVM丟擲異常資訊,然後中斷程式,異常還是沒有處理,只是丟擲了,可以提醒呼叫者來處理這個異常資訊。

例項

package demo1_Exception;

import java.io.FileNotFoundException;
import java.io.IOException;

/*
    異常的第一種處理方式:交給別人處理,自己並不處理。
       可以使用throws關鍵字來處理異常物件,會把異常物件宣告丟擲給
        方法的呼叫者處理(自己不處理,給別人處理),最終交給JVM處理--->中斷處理
 */
public class Test02_ThrowsException {
    public static void main(String[] args) throws IOException {
            read("C:\\readme.txt");
    }

    //如果定義功能時有問題發生需要報告給呼叫者。可以通過在方法上使用throws關鍵字進行宣告
    private static void read(String s) throws IOException {
        //非目標檔案,丟擲異常,在方法上宣告
        if(!s.equals("read.txt")){
            throw new FileNotFoundException("檔案不存在異常,找不到目標檔案");
        }

        //throws用於進行異常類的宣告,若該方法可能有多種異常情況產生,
        // 那麼在throws後面可以寫多個異常類,用逗號隔開。
        if(s.equals("hhreadme.txt")){
            throw  new IOException("檔案讀取錯誤");
        }
    }
}

=========================================================
//測試結果
Exception in thread "main" java.io.FileNotFoundException: 檔案不存在異常,找不到目標檔案
	at demo1_Exception.Test02_ThrowsException.read(Test02_ThrowsException.java:20)
	at demo1_Exception.Test02_ThrowsException.main(Test02_ThrowsException.java:13)

Process finished with exit code 1

異常處理方式二 

捕獲異常try...catch:異常處理第二種方式,自己處理。
捕獲異常:Java中對異常有針對性的語句進行捕獲異常,可以出現的異常進行指定方式的處理。

使用格式:

try{
     編寫可能會出現異常的程式碼
}catch(異常型別  e){
     處理捕獲到的異常
     //記錄日誌/列印異常資訊/繼續丟擲異常
}

注意:   1.try可能會丟擲多個異常物件,可以使用多個catch來處理這些異常物件。
               2. 如果try產生了異常,那麼就會執行catch中異常處理邏輯,執行完畢catch中處理邏輯,繼續執行try...catch之後的程式碼。
                   如果try中沒有產生異常,那麼就不會執行catch中的內容,直接執行try...ctach 之後的程式碼。

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

- public String getMessage():獲取異常的描述資訊,原因(提示給使用者的時候,就提示錯誤原因。

- public String toString():獲取異常的型別和異常描述資訊(不用)。
- public void printStackTrace():列印異常的跟蹤棧資訊並輸出到控制檯。

 這些檢視方法包含了異常的型別,異常的原因,以及異常出現的位置,在開發和除錯階段,都得使用printStackTrace

例項:

package demo1_Exception;

import java.io.FileNotFoundException;

/*
    異常的第二種處理方式:通過try...catch捕獲異常,自己處理

 */
public class Test03_TryCatchException {
    public static void main(String[] args) {
        //1.下面程式碼可能會出現異常,try..catch捕獲異常
        try {
            read("C:\\readme.txt");
        } catch (FileNotFoundException e) {
            //3.捕獲到異常,處理異常
            //4.try中丟擲的是什麼型別異常,catch中就定義什麼型別異常
            System.out.println(e);
        }

        System.out.println("over");
    }

    //2.出現編譯期異常,丟擲異常
    private static void read(String s) throws FileNotFoundException {
        if(!s.equals("read.txt")){
            throw new FileNotFoundException("目標檔案不存在");
        }
    }
}

finally程式碼塊

概念:有一些特定的程式碼無論異常是否發生,都需要執行。另外,因為異常會引發程式跳轉,導致有些語句執行不到。而finally就是解決這個問題的,在finally程式碼塊中存放的程式碼都是一定會被執行的。(比如在我們之後學習的IO流中,當打開了一個關聯檔案的資源,最後程式不管結果如何,都需要把這個資源關閉掉。 ) 
注意:finally不能單獨使用。

例項:
 

package demo1_Exception;

import java.io.FileNotFoundException;

//  finally程式碼塊
public class Test04_Finally {
    public static void main(String[] args) {
        try {
            read("readme.txt");
        }catch(FileNotFoundException e) {
            e.printStackTrace();
        }finally{
            System.out.println("不管程式怎樣,這裡都會被執行");
        }
        System.out.println("程式結束");
    }

    private static void read(String s) throws FileNotFoundException {
        if(s.equals("readmehh.txt")){
            throw new FileNotFoundException("目標檔案找不到");
        }
    }
}

=======================================================
//測試結果
不管程式怎樣,這裡都會被執行
程式結束

Process finished with exit code 0

其他異常注意事項

  • 執行時異常被丟擲可以不處理。即不捕獲也不宣告丟擲。

  • 如果finally有return語句,永遠返回finally中的結果,避免該情況.

  • 如果父類丟擲了多個異常,子類重寫父類方法時,丟擲和父類相同的異常或者是父類異常的子類或者不丟擲異常。

  • 父類方法沒有丟擲異常,子類重寫父類該方法時也不可丟擲異常。此時子類產生該異常,只能捕獲處理,不能宣告丟擲

自定義異常 

概念

為什麼需要自定義異常: 我們說了Java中不同的異常類,分別表示著某一種具體的異常情況,那麼在開發中總是有些異常情況是SUN沒有定義好的,此時我們根據自己業務的異常情況來定義異常類。
自定義異常類
         自定義一個業務邏輯異常:RegisterException.  一個註冊異常類。
如何定義異常類:
         1. 自定義一個編譯期異常: 自定義類 並繼承於java.lang.Exception
         2. 自定義一個執行時期的異常類:自定義類 並繼承於java.lang.RuntimeException。 

用法

 首先定義一個註冊異常類:

package demo1_Exception;
//註冊異常
public class Test01_RegisterException  extends Exception{
    //空參構造
    public Test01_RegisterException(){
    }

    //異常提示
    public Test01_RegisterException(String message){
        super(message);
    }
}

 定義一個測試類,模擬註冊操作:

package demo1_Exception;

import java.util.Scanner;

public class Test01 {
    public static void main(String[] args) {
        String[] str={"張三","王五","李四"};
        find_Exception(str);
    }

    private static void find_Exception(String[] str) {
        Scanner sc=new Scanner(System.in);
        for (String s : str) {
            try{
                checkUsername(s,str);
                //沒有異常,註冊成功
                System.out.println("註冊成功");
            }catch (Test01_RegisterException e){
                //處理異常
                e.printStackTrace();
            }
        }
    }

    //判斷當前賬戶是否被註冊
    //編譯器異常,聲明後丟擲
    private static boolean checkUsername(String s,String[] str) throws Test01_RegisterException {
        for (String s1 : str) {
            if(s1.equals(s)){
                throw new Test01_RegisterException("對不起,親,這個號已經被註冊了");
            }
        }
        return true;
    }
}

===========================================================
//測試結果一
請輸入一個賬號:
張三
demo1_Exception.Test01_RegisterException: 對不起,親,這個號已經被註冊了
	at demo1_Exception.Test01.checkUsername(Test01.java:32)
	at demo1_Exception.Test01.find_Exception(Test01.java:16)
	at demo1_Exception.Test01.main(Test01.java:8)

Process finished with exit code 0
===========================================================
//測試結果二
請輸入一個賬號:
趙六
註冊成功


 總結

          主要分清異常與error的概念,掌握異常處理的兩種方式和自定義異常,後期開發過程會經常用到自定義異常,其他內容瞭解即可。