更新時間:2022-12-27 12:09:13 來源:動力節點 瀏覽1396次
不同于編譯出錯,這里的異常指的是運行時異常,指的是程序已經編譯通過得到 class 文件了, 再由 JVM 執行過程中出現的錯誤,如我們之前常見的空指針異常、除0異常、數組越界異常等
如: 空指針異常
public static void main(String[] args) {
String str = null;
System.out.println(str.equals("1"));
}
執行結果:
NullPointerException 即為空指針異常
JDK中的內置異常類均在java.lang包下
java.lang.Throwable類是Java中所有異常或者錯誤的超類
LBYL:
Look Before You Leap. 在操作之前就做充分的檢查.
EAFP:
It's Easier to Ask Forgiveness than Permission. "事后獲取原諒比事前獲取許可更容易". 也就是先操作, 遇到問題再處理.
在java中主要是用EAFP方法,先做,如果有異常,我們再對異常處理
通常是用try - catch - finally進行捕獲異常
如果某方法可能存在異常,但不想在這里處理,我們就可以使用throws拋出異常給調用它的上一級,上一級在調用該方法時使用try - catch - finally 捕獲異常
try - catch -finally捕獲異常
try{
// 有可能出現異常的代碼塊
}catch ((異常類 異常對象)Exception e){
// 捕獲到該異常后執行的代碼
}finally{
// 無論是否有異常發生都會執行的代碼,善后處理
}
}
注意:
(1)catch語句可有0 - n個,即可以不寫catch語句,也可以寫多個,如果可能拋出的異常不止一個,就可以寫多個catch語句
(2)finally語句可有0或1個,無論是否捕獲到異常,均會執行finally語句,finally語句通常用于資源的關閉釋放等操作
(3)catch語句中,catch的小括號里即是寫捕獲到的異常類的異常對象,如上述代碼中的 Exception e,就是Exception 異常類的對象e
(4)這里要說明,Exception類是所有異常類的共同父類,所以當可能有多個異常或者具體是說明異常自己也不清楚的時候,可以用Exception類代替,但并不推薦這種寫法,因為這樣寫不便于排查異常原因,所以通常還是選擇用多個catch語句捕獲異常
異常處理流程:
程序先執行 try 中的代碼
如果 try 中的代碼出現異常, 就會結束 try 中的代碼, 看和 catch 中的異常類型是否匹配.
如果找到匹配的異常類型, 就會執行 catch 中的代碼如果沒有找到匹配的異常類型, 就會將異常向上傳遞到上層調用者.
無論是否找到匹配的異常類型, finally 中的代碼都會被執行到(在該方法結束之前執行).
如果上層調用者也沒有處理的了異常, 就繼續向上傳遞.一直到 main 方法也沒有合適的代碼處理異常, 就會交給 JVM 來進行處理, 此時程序就會異常終止.
(1)Error類是程序內部錯誤,程序員無法捕獲處理,所以 我們主要關注Exception類及其子類
(2)異常按照是否必須顯式處理又分為非受查異常和受查異常
非受查異常:
不強制要求處理,只有Error類和RuntimeException類及其子類是非受查異常,其他都是受查異常
受查異常:
必須使用try -catch捕獲異常或者throws拋出異常,否則會編譯報錯!!!
如果一個方法產生了異常,但并沒有對該異常進行處理,則會將異常拋出給其方法調用者,也就是說,只要異常沒有遇到處理方法,就會一直拋給調用它的上一級,直至被處理或者最后扔給JVM
在 JVM 中有一塊內存空間稱為 "虛擬機棧" 專門存儲方法之間的調用關系. 當代碼中出現異常的時候, 我們就可以使用 e.printStackTrace(); 的方式查看出現異常代碼的調用棧.
throws:用在方法聲明上,明確表示該方法會產生該異常,但方法本身并沒有對異常進行處理,所以該方法的異常會拋給調用它的上一級,所以 throws 關鍵字, 把可能拋出的異常顯式的標注在方法定義的位置. 從而提醒調用者要注意捕獲這些異常.
throw:用在方法內部,表示人為拋出異常,通常和自定義異常結合使用,在拋出異常后,該方法就會結束
如下面這段代碼塊,就是throw 和 throws 的用法
// throws用于方法聲明,提醒調用者注意對這一異常捕獲處理
public static int divide(int x, int y) throws ArithmeticException {
if (y == 0) {
// throw用于方法內部,人為拋出該異常
throw new ArithmeticException("拋出除 0 異常");
}
return x / y;
}
Java 中雖然已經內置了豐富的異常類, 但是我們實際場景中可能還有一些情況需要我們對異常類進行擴展, 創建符合我們實際情況的異常.
例如可能我們會用到具體的登錄異常,密碼錯誤異常等,這些都需要我們自己去定義
自定義異常通常會繼承自 Exception 或者 RuntimeException
繼承自 Exception 的異常默認是受查異常
繼承自 RuntimeException 的異常默認是非受查異常
下面以登錄異常為例,我們自己創建兩個異常類
import java.util.Scanner;
//自定義異常類
//以用戶登錄為例
public class Login {
private static String name = "阿衡";
private static String password = "123456";
public static void main(String[] args) {
try {
login();
System.out.println("登錄成功!");
} catch (nameException e) {
System.out.println("用戶名錯誤!");
// 打印錯誤堆棧信息
e.printStackTrace();
}
}
// 因為nameException繼承自受查異常,所以這里在拋出該異常時,方法聲明必須throws該異常交至上一級try-catch,否則會編譯報錯
public static void login() throws nameException {
System.out.println("請輸入您的用戶名:");
Scanner scanner = new Scanner(System.in);
String name1 = scanner.next();
System.out.println("請輸入用戶密碼:");
String password1 = scanner.next();
// 如果輸入的用戶名和預定的不一致,則拋出用戶名錯誤異常
if (!name1.equals(name)) {
throw new nameException("用戶名錯誤!");
}
// 如果密碼不一致,則拋出密碼錯誤異常
if (!password1.equals(password)) {
throw new passwordException("密碼錯誤!");
}
}
}
//用戶名錯誤異常
//受查異常,必須顯示使用try-catch或throws拋出
class nameException extends Exception {
public nameException(String msg) {
super(msg);
}
}
//密碼錯誤異常
//非受查異常,可以只用于拋出而不使用try-catch或throws處理
class passwordException extends RuntimeException {
public passwordException(String msg) {
super(msg);
}
}
值得注意的是,密碼錯誤異常繼承自非受查異常,所以我們可以不在login方法中用throws顯式拋給上一級,在main中也沒有顯式的用catch語句捕獲處理
但是,對于受查異常,我們看到,如果不處理會編譯報錯
最后,綜上,我們來個重點小總結:
(1)java用try-catch-finally捕獲異常進行處理
(2)throw關鍵字用于拋出異常
(3)throws關鍵字則是聲明有該異常且我未處理
(4)對于本方法的異常沒有處理的或者直接使用throw的我們都會拋給上一級讓上一級捕獲處理異常
(5)同時,我們可以自定義異常類
(6)最后,就是注意區分非受查異常(Runtimexception及其子類)和受查異常
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習