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