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