throw關鍵字
-
作用:可以使用throw關鍵字在指定的方法中拋出指定的異常
-
使用格式:
throw new xxxException(“異常產生的原因“)
-
注意事項
- throw關鍵字必須寫在方法的內部
- throw關鍵字后邊new的對象必須是 Exception或者 Exception的子類對象
- throw關鍵字拋出指定的異常對象,我們就必須處理這個異常對象。
- throw關鍵字后邊創建的是 RuntimeException或者是RuntimeException的子類對象,我們可以不處理,默認交給JW處理(打印異常對象,中斷程序)
- 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
-
java.util.Objects類是由一些靜態實用方法組成,這些方法是空指針安全的(即:容忍空指針的)
-
在源碼中對對象null值進行了拋出異常錯誤,源碼如下:
// 查看指定對象時不時null public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }
-
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("產生原因");
...
}
注意事項
- throws關鍵字必須寫在方法聲明處。
- throws關鍵字后邊聲明的異常必須是Exception或者是Exception的子類。
- 方法內部如果拋出了多個異常對象,那么throws后邊必須也聲明多個異常。如果批出的多個異常對象有子父類關系,那么直接聲明父類異常即可
- 調用了一個聲明拋出異常的方法,我們就必須處理聲明的異常,要么繼續使用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(異常類名 變量名) {
...
} ...
注意事項
- try中可能會拋出多個異常對象,那么就可以使用多個catch來處理這些異常對象。
- 如果try中產生了異常,那么就會執行ctch中的異常處理邏輯,執行完catch中的處理邏輯,會繼續執行try...catch之后的代碼。
- 如果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 {
...
}
注意事項
- finally不能單獨使用,必須要和try一起使用
- 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:
多個異常一次捕獲一次處理
實例理解:
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
子父類異常
- 如果父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異常或者是父類異常的子類或者不拋出異常。
- 父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。此時子類產生該異常,只能捕獲處理,不能聲明拋出。
如:
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();
}
}
}
自定義異常類的簡單練習
要求
模擬注冊操作,如果用戶名已存在,則拋出異常並提示:親,該用戶名已經被注冊。
分析
- 使用數組保存已經注冊過的用戶名
- 使用Scanner獲取用戶輸入的注冊的用戶名
- 定義一個方法,對用戶輸入中的注冊用戶名進行判斷,遍歷存儲已經注冊過用戶名的數組,獲取每一個用戶名,使用獲取到的用戶名和用戶輸入的用戶名比較
實現
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);
}
}
控制台輸入:李華
控制台輸出:
親,該用戶名已被注冊!
控制台輸入:靜香
控制台輸出:
恭喜您注冊成功!