深入理解java的異常情況
什么是異常?
在程序的運(yùn)行或者編譯時(shí),所產(chǎn)生的錯(cuò)誤統(tǒng)稱(chēng)為異常 (也叫Bug)
異常的存在形式
異常在java中以類(lèi)的形式存在,每一個(gè)異常類(lèi)都可以創(chuàng)建異常對(duì)象
我們平時(shí)看到的異常,都被封裝成一個(gè)類(lèi)
例如:0 為除數(shù),異常為:ArithmeticException
查看在線文檔會(huì)發(fā)現(xiàn):
Java異常體系
異常的分類(lèi)
異常分為:運(yùn)行時(shí)異常 和 編譯時(shí)異常
運(yùn)行時(shí)異常
運(yùn)行時(shí)異常又稱(chēng)為:非受查異常,指的是在程序運(yùn)行時(shí)所拋出的異常
特點(diǎn):Java編譯器不會(huì)檢查它,也就是說(shuō),當(dāng)程序中可能出現(xiàn)這類(lèi)異常,即使沒(méi)有用try-catch語(yǔ)句捕獲它,也沒(méi)有用throws子句聲明拋出它,也會(huì)編譯通過(guò)
編譯時(shí)異常
編譯時(shí)異常又稱(chēng)為:受查異常,在程序編譯時(shí)的異常
是RuntimeException以外的異常,類(lèi)型上都屬于Exception類(lèi)及其子類(lèi),從程序語(yǔ)法角度講是必須進(jìn)行處理的異常,如果不處理,程序就不能編譯通過(guò)
錯(cuò)誤 Error
是程序無(wú)法處理的錯(cuò)誤,表示運(yùn)行應(yīng)用程序中較嚴(yán)重問(wèn)題
錯(cuò)誤是預(yù)測(cè)不到的,如果應(yīng)用程序出現(xiàn)了Error,那么將無(wú)法恢復(fù),只能重新啟動(dòng)應(yīng)用程序
編譯時(shí)異常和運(yùn)行時(shí)異常的區(qū)別
編譯時(shí)異常 | 運(yùn)行時(shí)異常 | |
---|---|---|
發(fā)生概率 | 比較高 | 比較低 |
處理方式 | 需要在運(yùn)行之前對(duì)其進(jìn)行 預(yù)處理 | 沒(méi)必要提前進(jìn)行預(yù)處理 |
常見(jiàn)的異常
我們之前已經(jīng)接觸了一些異常,常見(jiàn)的異常還是有必要記住的
0為除數(shù)(算數(shù)異常)
int a = 10 / 0;
數(shù)組下標(biāo)越界(數(shù)組下標(biāo)越界異常)
int[] array = {1,2,3}; System.out.println(array[4]);
訪問(wèn) null(空指針異常)
空指針異常出現(xiàn)的概率非常高?。?/p>
int[] array = {1,2,3}; array = null; System.out.println(array[2]);
防御式編程
程序出現(xiàn)問(wèn)題的時(shí)候及時(shí)通知程序猿,主要有兩種主要的方式:
BYBL
Look Before You Leap
,在操作之前就做充分的檢查
舉例:一個(gè)男孩子很喜歡一個(gè)女孩子,想要拉女孩子的手,提前問(wèn):我可以拉你的手嘛?
EAFP
It's Easier to Ask Forgiveness than Permission
,“事后獲取原諒比事前獲取許可更容易”,也就是先操作,遇到問(wèn)題再處理
舉例:男孩子先拉的女孩子的手,女孩子很生氣,呼了一巴掌,男孩子再回來(lái)巴拉巴拉道歉
異常的核心就是EAFP
Java處理異常的語(yǔ)法
異常拋出—throws
指編程人員主動(dòng)拋出一個(gè)異常
任何Java代碼都可以拋出異常,在方法聲明的位置上使用 throws 關(guān)鍵字拋出,拋給方法的調(diào)用者來(lái)處理,這種處理異常的態(tài)度:上報(bào)
舉例:
public static void testThrows() throws NullPointerException { Integer p = null; System.out.println(p + 1); }
注意:
- 方法的調(diào)用者負(fù)責(zé)處理該異常
- 在定義方法時(shí),把異常拋出就是為了提醒方法的使用者,有異常需要預(yù)處理
- 如果異常對(duì)象是 非RuntimeException,則需要在方法申明時(shí)加上該異常的拋出
- 即需要加上 throws 語(yǔ)句 或者 在方法體內(nèi) try catch 處理該異常,否則編譯報(bào)錯(cuò)
- 執(zhí)行到 throw 語(yǔ)句,后面的語(yǔ)句塊不再執(zhí)行
異常捕獲—try…catch
這個(gè)異常不會(huì)上報(bào),自行處理,異常拋到此處為止,不再上拋
try { //可能出現(xiàn)異常的代碼 } catch (Exception1 e) { //參數(shù):異常的類(lèi)型 e //捕獲try當(dāng)中可能出現(xiàn)的異常 } catch (Exception2 e) { //參數(shù):異常的類(lèi)型 e //捕獲try當(dāng)中可能出現(xiàn)的異常 } finally { }
舉例:
int[] array = {2,4,6,8}; try{ System.out.println(array[4]); } catch (ArrayIndexOutOfBoundsException e){ System.out.println("捕獲到數(shù)組越界異常!"); }
對(duì)比:
注意:
- try{ } 包含了可能出現(xiàn)異常的代碼
- catch 可以有一個(gè)或多個(gè),catch中是捕獲 try 當(dāng)中可能出現(xiàn)的異常,可以通過(guò) catch 捕獲多個(gè)異常
- catch 塊當(dāng)中,一定要捕獲相應(yīng)的異常,如果程序拋出的異常在 catch 塊當(dāng)中不能被捕獲,則會(huì)交給JVM來(lái)處理異常,程序便會(huì)異常終止
- 當(dāng) try 中的代碼出現(xiàn)異常時(shí),try 里異常之后的代碼不會(huì)執(zhí)行,馬上會(huì)跳轉(zhuǎn)到相應(yīng)的catch語(yǔ)句塊中,如果沒(méi)有異常便不會(huì)跳轉(zhuǎn)
- 不管是否出現(xiàn)異常,finally{ } 里的代碼都執(zhí)行,finally和catch可以分開(kāi)使用,但finally必須和try一塊使用
- 不建議直接捕獲 Exception 異常,要捕獲就捕獲具體的
- 不建議在 finally 中出現(xiàn) return語(yǔ)句
- catch 只能處理對(duì)應(yīng)種類(lèi)的異常
try 負(fù)責(zé)回收資源
Scanner scan = new Scanner(System.in); try{ int n = scan.nextInt(); System.out.println(10/n); } catch (ArithmeticException e){ e.printStackTrace(); } finally { scan.close(); }
在Idea里,會(huì)發(fā)現(xiàn) try 背景色會(huì)加深,將鼠標(biāo)放在 try,按 Alt + Enter
出現(xiàn)上圖,回車(chē)即可!
然后代碼就會(huì)自動(dòng)被優(yōu)化:
即:將 Scan 對(duì)象在 try( )中創(chuàng)建,就能保證在 try 執(zhí)行完畢后自動(dòng)調(diào)用 Scanner 的 close 方法
向上傳遞,處理異常
先看代碼:
public static void func(){ int[] array = {2,4,6,8}; System.out.println(array[4]); } public static void main(String[] args) { func(); }
上述代碼,func 方法里存在數(shù)組越界異常,但并沒(méi)有處理,到 main 中調(diào)用 func 方法,由于 main方法里也沒(méi)有處理該異常,則會(huì)交給 JVM,那么程序一運(yùn)行,遇到異常,直接就會(huì)終止
改進(jìn):
public static void func(){ int[] array = {2,4,6,8}; System.out.println(array[4]); } public static void main(String[] args) { try { func(); } catch (ArrayIndexOutOfBoundsException e){ e.printStackTrace(); } finally { System.out.println("hahaha"); }
異常的傳遞是可以沿著棧向上傳遞的,方法是要在棧上開(kāi)辟內(nèi)存的
處理流程
- 程序先執(zhí)行 try 中的代碼
- 若 try 中的代碼出現(xiàn)異常,就會(huì)結(jié)束 try 中的代碼,看和 catch 中的異常類(lèi)型是否匹配
- 若找到匹配的異常類(lèi)型,就會(huì)執(zhí)行 catch 中的代碼
- 若沒(méi)有找到匹配的異常類(lèi)型,就會(huì)將異常向上傳遞到上層調(diào)用者
- 無(wú)論是否找到匹配的異常類(lèi)型,finally 中的代碼都會(huì)被執(zhí)行到(在該方法結(jié)束之前執(zhí)行)
- 若上層調(diào)用者也沒(méi)有處理的了異常,就繼續(xù)向上傳遞
- 一直到 main 方法也沒(méi)有合適的代碼處理異常,就會(huì)交給 JVM 來(lái)進(jìn)行處理,此時(shí)程序就會(huì)異常終止
自定義異常類(lèi)
自定義異常類(lèi)步驟:
編寫(xiě)一個(gè)類(lèi)繼承 Exception 或者 RuntimeException提供兩個(gè) 構(gòu)造方法,一個(gè)無(wú)參數(shù)的,一個(gè)帶有 String 參數(shù)的
class MyException extends RuntimeException{ //構(gòu)造方法 public MyException() { super(); } public MyException(String message) { super(message); } }
自己玩~~
public static void func(int x){ if(x == 10){ throw new MyException("x==10"); } } public static void main(String[] args) { try { func(10); } catch (MyException e){ e.printStackTrace(); } }
輸出結(jié)果:
注意事項(xiàng):
- 一定要繼承一個(gè)父類(lèi)異常,通常是 Exception / RuntimeException
- 一般建議繼承Exception,好處是必須要處理異常
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
springMVC的RequestMapping請(qǐng)求不到路徑的解決
這篇文章主要介紹了springMVC的RequestMapping請(qǐng)求不到路徑的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08SpringMVC自定義攔截器實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了SpringMVC自定義攔截器實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05詳解spring cloud hystrix請(qǐng)求緩存(request cache)
這篇文章主要介紹了詳解spring cloud hystrix請(qǐng)求緩存(request cache),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05詳談java線程與線程、進(jìn)程與進(jìn)程間通信
下面小編就為大家?guī)?lái)一篇詳談java線程與線程、進(jìn)程與進(jìn)程間通信。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04