1. 程式人生 > 實用技巧 >Java自學第7期——異常(Exception)

Java自學第7期——異常(Exception)

1.概念:

  • 異常 :指的是程式在執行過程中,出現的非正常的情況,終會導致JVM的非正常停止。
  • 在Java等面向物件的程式語言中,異常本身是一個類,
    產生異常就是建立異常物件並丟擲了一個異常物件。
  • Java處理異常的方式是中斷處理。
    異常指的並不是語法錯誤,語法錯了,編譯不通過,不會產生位元組碼檔案,根本不能執行.

2.Throwable體系:

  • 所有異常或錯誤的超類:java.lang.Throwable ,其下有兩個子類:
    java.lang.Error 與 java.lang.Exception
    平常所說的異常指 java.lang.Exception 。
  • 異常與錯誤的區別
    Error:無法通過處理解決的叫錯誤,只能事先避免。
    Exception:異常產生後程序員可以通過程式碼的方式糾正,使程式繼續執行,是必須要處理的。
  • Throwable中的常用方法:
    public void printStackTrace() :列印異常的詳細資訊。
    包含了異常的型別,異常的原因,還包括異常出現的位置,
    在開發和除錯階段,都得使用printStackTrace。
    public String getMessage() :獲取發生異常的原因。 提示給使用者的時候,就提示錯誤原因。
    public String toString() :獲取異常的型別和異常描述資訊(不用)。
  • 出現異常,把異常的類名複製到API中查詢

3.異常的分類

編譯時期異常:checked異常。在編譯時期,就會檢查,如果沒有處理異常,則編譯失敗。(如日期格式化異常)
執行時期異常:runtime異常。在執行時期,檢查異常.在編譯時期,執行異常不會編譯器檢測(不報錯)。(如數學異常)

public class Demo01 {
    public static void main(String[] args) {
        int[] array = {1,2,3};
/*      System.out.println(array[3]);
異常如下:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
	at Exception.Demo01.main(Demo01.java:30)
其中,java.lang.ArrayIndexOutOfBoundsException表示異常的型別
Index 3 out of bounds for length 3表示異常的原因
at Exception.Demo01.main(Demo01.java:30)表示異常的位置
 */
    }
}

4.異常的處理

在java中,提供了一個throw關鍵字,它用來丟擲一個指定的異常物件。那麼,丟擲一個異常具體如何操作呢?

  1. 建立一個異常物件。封裝一些提示資訊(資訊可以自己編寫)。
  2. 需要將這個異常物件告知給呼叫者,通過關鍵字throw完成。throw異常物件。
    throw用在方法內,用來丟擲一個異常物件,將這個異常物件傳遞到呼叫者處,並結束當前方法的執行。
  • 丟擲異常:
    throw new 異常類名(引數)
  • 判斷引數合法性,看引數是否為空,統一使用Object類裡的靜態方法requireNonNull();
public class Demo02 {
    public static void main(String[] args) {
        int[] array = {1,2,3};
        /*
        此時index=3越界了,看看執行結果
    Exception in thread "main" java.lang.IndexOutOfBoundsException: 小老弟,你給的角標越陣列的界了
	at Exception.Demo02.getElement(Demo02.java:30)
	at Exception.Demo02.main(Demo02.java:23)
         */

        int num = getElement(array,3);
        System.out.println(num);

    }
    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;
    }
    public static void method(Object obj){
        //對傳遞的obj進行引數的合法性判斷
        //傳給Object的方法requireNonNull
        Objects.requireNonNull(obj);
    }
}
  • 宣告異常關鍵字throws
    異常處理的第一種方式:交給別人處理
    宣告異常:將問題標識出來,報告給呼叫者。如果方法內通過throw丟擲了編譯時異常,而沒有捕獲處理(稍後講 解該方式),
    那麼必須通過throws進行宣告,讓呼叫者去處理。
    關鍵字throws運用於方法宣告之上,用於表示當前方法不處理異常,而是提醒該方法的呼叫者來處理異常(丟擲異常).
    宣告異常格式:
    修飾符 返回值型別 方法名(引數) throws 異常類名1,異常類名2…{ }

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

public class Demo03 {
    public static void main(String[] args) throws IOException{//此處注意
        read("a.txt");
    }
    public static void read(String path) throws FileNotFoundException, IOException {
        if (!path.equals("a.txt")){
            throw new FileNotFoundException("檔案不存在");
        }
        if (!path.equals("b.txt")){
            throw new IOException("檔案不存在");
        }
    }
}
  • 捕獲異常:try...catch
    如果異常出現的話,會立刻終止程式,所以我們得處理異常:

    1. 該方法不處理,而是宣告丟擲,由該方法的呼叫者來處理(throws)。
    2. 在方法中使用try-catch的語句塊來處理異常。
      try-catch的方式就是捕獲異常。
  • 捕獲異常:Java中對異常有針對性的語句進行捕獲,可以對出現的異常進行指定方式的處理。
    捕獲異常語法如下:
    try(
    可能存在異常的程式碼
    )catch(定義一個變數,用來接受try中異常的物件){
    處理異常的程式碼
    }
    ...
    catch(異常類名 變數名){
    }
    注意:try和catch都不能單獨使用,必須連用。try中可能丟擲多個異常物件,那麼可以使用多個catch處理

  • 如何獲取異常的資訊:Throwable類中定義了三個檢視方法:
    public String getMessage() :返回此throwable的簡短描述。
    public String toString() :返回此throwable的詳細描述。
    public void printStackTrace() :列印異常物件,預設此方法,列印的異常資訊是最全面的。
    包含了異常的型別,異常的原因,還包括異常出現的位置,在開發和除錯階段,都得使用printStackTrace();

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

  • finally的語法:
    try...catch....finally:自身需要處理異常,最終還得關閉資源。
    注意:
    finally不能單獨使用。
    只有try或者catch中呼叫了退出JVM的方法時finally才不會執行,否則finally永遠會執行

public class Demo04_try_catch {
    public static void main(String[] args) {
        try {
            readProblem("a.tx");
        } catch (IOException obj) {//try中什麼型別異常,括號內就寫什麼型別
            System.out.println("1:"+obj.getMessage());
            System.out.println("2:"+obj.toString());
            //printStackTrace最全面,預設列印異常物件也是使用該方法
            obj.printStackTrace();
            System.out.println("3:"+obj);
        }finally{//有一些特定的程式碼無論異常是否發生       論程式碼是否異常,fanally程式碼塊都會執行
            System.out.println("fianlly程式碼塊執行!");
        }


    }
    public static void readProblem(String path1) throws IOException {
        if (!path1.equals("b.txt")){
            throw new IOException("檔案字尾名不對");
        }
    }
}

5.異常注意事項

(一).捕獲多個異常如何處理

  1. 多個異常分別處理。
  2. 多個異常一次捕獲,多次處理。
  3. 多個異常一次捕獲一次處理。一般使用一次捕獲多次處理方式
    注意:
    a.多個catch內異常類不能相同,且若有子父類關係,子類需要寫在上面
    b.如果父類丟擲了多個異常,子類重寫父類方法時,丟擲和父類相同的異常或者是父類異常的子類或者不丟擲異常。
    c.父類方法沒有丟擲異常,子類重寫父類該方法時也不可丟擲異常。此時子類產生該異常,只能捕獲處理,不能宣告丟擲.
    d.執行時異常(runtime)被丟擲可以不處理。即不捕獲也不宣告丟擲。
    e.如果finally有return語句,永遠返回finally中的結果,即避免在finally中寫return語句.
public class Demo05_Tips {
    public static void main(String[] args){
       try{
           int[] arr1 = {1,2,3};
           System.out.println(arr1[3]);
            //try裡多個異常一次捕獲
           List<Integer> list = List.of(1,2,3);
           System.out.println(list.get(3));
       } catch(ArrayIndexOutOfBoundsException a){//通過catch括號內參數型別接受對應異常物件
           System.out.println(a);
       } catch (IndexOutOfBoundsException a){
           System.out.println(a);
       }
    }
    public void show0() throws FileNotFoundException{};
    public void show1() throws IndexOutOfBoundsException{};
    public void show2() throws ArrayIndexOutOfBoundsException{};
    public void show3() throws IOException{};
}
class zi extends Demo05_Tips{
    //子類重寫父類方法時,可以丟擲和父類相同的異常
        public void show0() throws FileNotFoundException{};
        //丟擲父類異常類的子類
        public void show1() throws ArrayIndexOutOfBoundsException{};
        //可以不丟擲異常
        public void show2() {};
    }

定義好異常類後,進行測試:
如果使用者註冊重複,返回異常資訊

6.自定義異常類:

java提供的異常類不夠,需要進行自定義異常類:

public class ***Exception extends Exception/RuntimeException{
        //新增一個空引數的構造方法
        //新增一個帶異常資訊的構造方法
}

注意:
1.自定義異常類一般以Exception結尾,表示這是異常類
2.自定義異常類必須繼承Exception類或者RuntimeException類,
繼承Exception類就是編譯期異常,選擇throws或者try catch
繼承RuntimeException就是執行期異常,交給虛擬機器處理.

//首先定義一個登陸異常類RegisterException:
//此處繼承異常類,本身類名是就是自定義異常類名
public class RegisterException extends Exception{
    //模擬註冊操作,如果使用者名稱已存在,則丟擲異常並提示:親,該使用者名稱已經被註冊。
    //原有使用者名稱
    //新增一個空引數的構造方法
    public RegisterException() {
        super();
    }
    //新增一個帶異常資訊的構造方法,讓父類來處理
    public RegisterException(String s){
        super(s);
    }
}

使用:

public class Demo07_test {

    static String[] username0 = {"1","2","3"};
    public static void main(String[] args) throws RegisterException {//宣告自定義異常類
        System.out.println("請輸入使用者名稱");
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        Check(str);
    }
    public static void Check(String str) throws RegisterException {//宣告自定義異常類
        for (String name : username0){
            if (name.equals(str)){
                throw new RegisterException("該使用者名稱已經被註冊");
            }
        }

        System.out.println("註冊成功。");
    }
}