對 Java 異常處理的學習


throw關鍵字

  1. 作用:可以使用throw關鍵字在指定的方法中拋出指定的異常

  2. 使用格式:

    throw new xxxException(“異常產生的原因“)
    
  3. 注意事項

    1. throw關鍵字必須寫在方法的內部
    2. throw關鍵字后邊new的對象必須是 Exception或者 Exception的子類對象
    3. throw關鍵字拋出指定的異常對象,我們就必須處理這個異常對象。
    4. throw關鍵字后邊創建的是 RuntimeException或者是RuntimeException的子類對象,我們可以不處理,默認交給JW處理(打印異常對象,中斷程序)
    5. throw關鍵字后邊創建的是編譯異常,我們就必須處理這個異常,要么 throws,要么try...catch

舉例

例子1

public class DemoThrow {
    public static void main(String[] args) {
        int[] array = {};

        int element = DemoThrow.getElement(array, 1);
    }

    public static int getElement(int[] array, int index) {
        if (array.length == 0) {
            throw new NullPointerException("傳入的數組為空");
        } else if (index == 0 || index > array.length - 1) {
            throw new ArrayIndexOutOfBoundsException("傳遞的索引超出了數組的適用范圍");
        } else {
            return array[index];
        }
    }
}
拋出錯誤:
Exception in thread "main" java.lang.NullPointerException: 傳入的數組為空
    at XXX.DemoThrow.getElement(DemoThrow.java:10)
    at XXX.DemoThrow.main(DemoThrow.java:5)

例子2

public class DemoThrow {
    public static void main(String[] args) {
        int[] array = {1, 2, 3};

        int element = DemoThrow.getElement(array, 100);
    }

    public static int getElement(int[] array, int index) {
        if (array.length == 0) {
            throw new NullPointerException("傳入的數組為空");
        } else if (index == 0 || index > array.length - 1) {
            throw new ArrayIndexOutOfBoundsException("傳遞的索引超出了數組的適用范圍");
        } else {
            return array[index];
        }
    }
}
拋出錯誤:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 傳遞的索引超出了數組的適用范圍
    at XXX.DemoThrow.getElement(DemoThrow.java:12)
    at XXX.DemoThrow.main(DemoThrow.java:5)

Objects非空判斷requireNonNull

  1. java.util.Objects類是由一些靜態實用方法組成,這些方法是空指針安全的(即:容忍空指針的)

  2. 在源碼中對對象null值進行了拋出異常錯誤,源碼如下:

    // 查看指定對象時不時null
    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }
    
  3. requireNonNull方法的使用

    import java.util.Objects;
    
    public class DemoObjectsNonNull {
        public static void main(String[] args) {
            String s = null;
            Objects.requireNonNull(s, "傳入的參數為空");
        }
    }
    
    拋出錯誤:
    Exception in thread "main" java.lang.NullPointerException: 傳入的參數為空
        at java.util.Objects.requireNonNull(Objects.java:228)
        at XXX.DemoObjectsNonNull.main(DemoObjectsNonNull.java:6)
    

自定義非空判斷

public class DemoObjectsNonNull {
    public static void main(String[] args) {
        String s = null;
        methodNonNull(s);
    }
    
    public static <E> void methodNonNull(E e) {
        if (e == null) {
            throw new NullPointerException("傳入的參數為空");
        }
    }
}
拋出錯誤:
Exception in thread "main" java.lang.NullPointerException: 傳入的參數為空
    at XXX.DemoObjectsNonNull.methodNonNull(DemoObjectsNonNull.java:9)
    at XXX.DemoObjectsNonNull.main(DemoObjectsNonNull.java:5)

throws 關鍵字處理異常

throws作用

當方法內部拋出異常對象的時候,那么我們就必須處理這個異常對象。可以使用 throws關鍵字處理異常對象,它會把異常對象聲明拋給方法的調用者處理(自己不處理,紿別人處理)最終交給JVM-->中斷處理

使用格式

修飾符 返回值類型 方法名(參數列表) throws AaaException, BbbException ... {
    throw new AaaException("產生原因");
    throw new BbbException("產生原因");
    ...
}

注意事項

  1. throws關鍵字必須寫在方法聲明處。
  2. throws關鍵字后邊聲明的異常必須是Exception或者是Exception的子類。
  3. 方法內部如果拋出了多個異常對象,那么throws后邊必須也聲明多個異常。如果批出的多個異常對象有子父類關系,那么直接聲明父類異常即可
  4. 調用了一個聲明拋出異常的方法,我們就必須處理聲明的異常,要么繼續使用throws聲明拋出,交給方法的調用者處理,最終交給JVM,要么try...catch自己處理異常。

舉例

例子1:

import java.io.FileNotFoundException;

public class Demo01Throws {
    public static void main(String[] args) throws FileNotFoundException{
        String s = "/Users/data.txt";
        readFile(s);
    }

    public static void readFile(String s) throws FileNotFoundException {
        if ("/Users/data.txt".equals(s)) {
            System.out.println("傳入的參數是'/Users/data.txt'");
        } else {
            throw new FileNotFoundException("傳入的參數不是'/Users/data.txt'");
        }
    }
}
輸出結果:
傳入的參數是'/Users/data.txt'

例子2:

import java.io.FileNotFoundException;

public class Demo01Throws {
    public static void main(String[] args) throws FileNotFoundException{
        String s = "/Users/data";
        readFile(s);
    }

    public static void readFile(String s) throws FileNotFoundException {
        if ("/Users/data.txt".equals(s)) {
            System.out.println("傳入的參數是'/Users/data.txt'");
        } else {
            throw new FileNotFoundException("傳入的參數不是'/Users/data.txt'");
        }
    }
}
拋出錯誤:
Exception in thread "main" java.io.FileNotFoundException: 傳入的參數不是'/Users/data.txt'
    at XXX.Demo01Throws.readFile(Demo01Throws.java:11)
    at XXX.Demo01Throws.main(Demo01Throws.java:6)

try catch 關鍵字處理異常

使用格式

try {
    ...
} catch (異常類名 變量名) {
    ...
}
...
catch(異常類名 變量名) {
    ...
} ...

注意事項

  1. try中可能會拋出多個異常對象,那么就可以使用多個catch來處理這些異常對象。
  2. 如果try中產生了異常,那么就會執行ctch中的異常處理邏輯,執行完catch中的處理邏輯,會繼續執行try...catch之后的代碼。
  3. 如果try中沒有產生異常,那么就不會執行catch中異常的處理邏輯,執行完try中的代碼,繼續執行try...catch之后的代碼。

舉例

public class Demo01TryCatch {
    public static void main(String[] args) {

        try {
            String[] strings = {};
            System.out.println(strings[100]);
        } catch (ArrayIndexOutOfBoundsException e) {
            // 數組索引越界異常
            System.out.println("Exception in thread \"main\" java.lang.ArrayIndexOutOfBoundsException");
        } catch (NullPointerException e) {
            // 空指針異常
            System.out.println("Exception in thread \"main\" java.lang.NullPointerException");
        }
        System.out.println("程序執行完成");
    }
}
輸出結果:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
程序執行完成

Throwable類中3個異常處理的方法

public void printStackTrace()
// 打印異常的跟蹤棧信息,並輸出到控制台。包含了異常的類型,異常的原因,還包括異常出現的位置。在開發和調試階段都得使用printStackTrace。
public String getMessage()
// 獲取發生異常的原因。提示給用戶時候就提示誤原因。
public String toString()
// 獲取異常的類型和異常描述信息。

這三個方法源碼:

public void printStackTrace() {
        printStackTrace(System.err);
}
public String getMessage() {
        return detailMessage;
}
public String toString() {
        String s = getClass().getName();
        String message = getLocalizedMessage();
        return (message != null) ? (s + ": " + message) : s;
}

三個方法舉例

public class DemoTryCatch {
    public static void main(String[] args) {
        try {
            String[] strings = new String[10];
            getElement(strings, 10);
        } catch (ArrayIndexOutOfBoundsException e) {
            // 獲取發生異常的原因
            System.out.println(e.getMessage());
            // 獲取異常的類型和異常描述信息
            System.out.println(e.toString());
            // 獲取棧的跟蹤信息(異常的類型、異常的原因、異常出現的位置)
            e.printStackTrace();
        }
    }

    public static String getElement(String[] array, int index) {
        if (array.length == 0) {
            throw new NullPointerException("傳入的數組為空");
        } else if (index == 0 || index > array.length - 1) {
            throw new ArrayIndexOutOfBoundsException("傳遞的索引超出了數組的適用范圍");
        } else {
            return array[index];
        }
    }
}
控制台輸出:
傳遞的索引超出了數組的適用范圍
java.lang.ArrayIndexOutOfBoundsException: 傳遞的索引超出了數組的適用范圍
java.lang.ArrayIndexOutOfBoundsException: 傳遞的索引超出了數組的適用范圍
    at XXX.DemoTryCatch.getElement(DemoTryCatch.java:19)
    at XXX.DemoTryCatch.main(DemoTryCatch.java:5)

finally代碼塊

格式

try {
    ...
} catch (異常類名 變量名) {
    ...
}
...
catch(異常類名 變量名) {
    ...
} finally {
    ...
}

注意事項

  1. finally不能單獨使用,必須要和try一起使用
  2. finally一般用於資源釋放(資源回收),無論程序是否出現異常,最后都要釋放IO

舉例

public class DemoFinally {
    public static void main(String[] args) {

        try {
            String[] strings = {};
            System.out.println(strings[100]);
        } catch (ArrayIndexOutOfBoundsException e) {
            // 獲取異常的類型和異常描述信息
            System.out.println(e.toString());
        } finally {
            System.out.println("程序執行完成");
        }

    }
}
控制台輸出:
java.lang.ArrayIndexOutOfBoundsException: 100
程序執行完成

多異常的捕獲處理

多個異常分別處理

實例理解:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Demo01ManyException {
    public static void main(String[] args) {

        try {
            int[] array = {1, 2, 3};
            int a = array[3];
        }
        catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(e.toString());
        }


        try {
            List<Integer> list = new ArrayList<>();
            Collections.addAll(list, 1, 2, 3);
            int b = list.get(3);
        }
        catch (IndexOutOfBoundsException e) {
            System.out.println(e.toString());
        }
    }
}
控制台輸出:
java.lang.ArrayIndexOutOfBoundsException: 3
java.lang.IndexOutOfBoundsException: Index: 3, Size: 3

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

實例理解:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Demo01ManyException {
    public static void main(String[] args) {

        try {
            int[] array = {1, 2, 3};
            int a = array[3];

            List<Integer> list = new ArrayList<>();
            Collections.addAll(list, 1, 2, 3);
            int b = list.get(3);
        }
        catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(e.toString());
        }
        catch (IndexOutOfBoundsException e) {
            System.out.println(e.toString());
        }
        
    }
}
控制台輸出:
java.lang.ArrayIndexOutOfBoundsException: 3

注意事項

一個try,多個catch,catch里面定義的異常變量,如果有子父類關系,那么子類的異常變量必須寫在前面,否則會報錯

ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException

img

img

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

實例理解:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Demo01ManyException {
    public static void main(String[] args) {

        try {
            int[] array = {1, 2, 3};
            int a = array[3];

            List<Integer> list = new ArrayList<>();
            Collections.addAll(list, 1, 2, 3);
            int b = list.get(3);
        }
        catch (Exception e) {
            System.out.println(e.toString());
        }

    }
}
控制台輸出:
java.lang.ArrayIndexOutOfBoundsException: 3

finally有return語句

如果finally中有return語句,只會返回finally中的值。

如:

public class Demo01FinallyReturn {
    public static void main(String[] args) {
        System.out.println(Demo01FinallyReturn.method());
    }

    public static String method() {
        try {
            String s = "abc";
            return s;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            String s = "ABC";
            return s;
        }
    }
}
控制台輸出:
ABC

子父類異常

  1. 如果父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異常或者是父類異常的子類或者不拋出異常。
  2. 父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。此時子類產生該異常,只能捕獲處理,不能聲明拋出。

如:

public class Fu {

    public static void method1() throws NullPointerException, ClassCastException { }

    public static void method2() throws IndexOutOfBoundsException { }

    public static void method3() { }

    public static void method4() { }

}
public class Zi extends Fu {

    /**
     * 子類重寫父類方法時,拋出和父類相同的異常
     * @throws NullPointerException 空指針異常
     * @throws ClassCastException 類強制轉換異常
     */
    public static void method1() throws NullPointerException, ClassCastException { }

    /**
     * 子類重寫父類方法時,拋出父類異常的子類
     * @throws ArrayIndexOutOfBoundsException 索引越界異常
     */
    public static void method2() throws ArrayIndexOutOfBoundsException { }

    /**
     * 子類重寫父類方法時,不拋出異常
     */
    public static void method3() { }

    /**
     * 父類方法沒有拋出異常,子類重寫父類方法時,也不可以拋出異常
     * 只能捕獲處理,不能聲明拋出
     */
    public static void method4(){
        try {
            throw new Exception("編譯期異常");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

自定義異常類的簡單練習

要求

模擬注冊操作,如果用戶名已存在,則拋出異常並提示:親,該用戶名已經被注冊。

分析

  1. 使用數組保存已經注冊過的用戶名
  2. 使用Scanner獲取用戶輸入的注冊的用戶名
  3. 定義一個方法,對用戶輸入中的注冊用戶名進行判斷,遍歷存儲已經注冊過用戶名的數組,獲取每一個用戶名,使用獲取到的用戶名和用戶輸入的用戶名比較

實現

import java.util.Scanner;

public class MyUsersException {

    private static String[] names = {"小紅", "小明", "李華", "小軍", "大雄"};

    public static void registerUser(String scannerUser) {
        for (String name : names) {
            if (name.equals(scannerUser)) {
                try {
                    throw new RuntimeException("親,該用戶名已被注冊!");
                } catch (RuntimeException e) {
                    System.out.println(e.getMessage());
                    return;
                }
            }
        }
        System.out.println("恭喜您注冊成功!");
    }

    public static void main(String[] args) throws RuntimeException{
        Scanner scn = new Scanner(System.in);
        System.out.print("輸入要注冊的用戶名:");
        String registerUserName = scn.next();
        MyUsersException.registerUser(registerUserName);
    }
}
控制台輸入:李華
控制台輸出:
親,該用戶名已被注冊!
控制台輸入:靜香
控制台輸出:
恭喜您注冊成功!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM