深入理解java的異常情況
什么是異常?
在程序的運行或者編譯時,所產(chǎn)生的錯誤統(tǒng)稱為異常 (也叫Bug)
異常的存在形式
異常在java中以類的形式存在,每一個異常類都可以創(chuàng)建異常對象
我們平時看到的異常,都被封裝成一個類
例如:0 為除數(shù),異常為:ArithmeticException
查看在線文檔會發(fā)現(xiàn):

Java異常體系

異常的分類
異常分為:運行時異常 和 編譯時異常
運行時異常
運行時異常又稱為:非受查異常,指的是在程序運行時所拋出的異常
特點:Java編譯器不會檢查它,也就是說,當(dāng)程序中可能出現(xiàn)這類異常,即使沒有用try-catch語句捕獲它,也沒有用throws子句聲明拋出它,也會編譯通過
編譯時異常
編譯時異常又稱為:受查異常,在程序編譯時的異常
是RuntimeException以外的異常,類型上都屬于Exception類及其子類,從程序語法角度講是必須進(jìn)行處理的異常,如果不處理,程序就不能編譯通過
錯誤 Error
是程序無法處理的錯誤,表示運行應(yīng)用程序中較嚴(yán)重問題
錯誤是預(yù)測不到的,如果應(yīng)用程序出現(xiàn)了Error,那么將無法恢復(fù),只能重新啟動應(yīng)用程序
編譯時異常和運行時異常的區(qū)別
| 編譯時異常 | 運行時異常 | |
|---|---|---|
| 發(fā)生概率 | 比較高 | 比較低 |
| 處理方式 | 需要在運行之前對其進(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)問題的時候及時通知程序猿,主要有兩種主要的方式:
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)度:上報
舉例:
public static void testThrows() throws NullPointerException {
Integer p = null;
System.out.println(p + 1);
}
注意:
- 方法的調(diào)用者負(fù)責(zé)處理該異常
- 在定義方法時,把異常拋出就是為了提醒方法的使用者,有異常需要預(yù)處理
- 如果異常對象是 非RuntimeException,則需要在方法申明時加上該異常的拋出
- 即需要加上 throws 語句 或者 在方法體內(nèi) try catch 處理該異常,否則編譯報錯
- 執(zhí)行到 throw 語句,后面的語句塊不再執(zhí)行
異常捕獲—try…catch
這個異常不會上報,自行處理,異常拋到此處為止,不再上拋
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)異常時,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,那么程序一運行,遇到異常,直接就會終止
改進(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)行處理,此時程序就會異常終止
自定義異常類
自定義異常類步驟:
編寫一個類繼承 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é)果:

注意事項:
- 一定要繼承一個父類異常,通常是 Exception / RuntimeException
- 一般建議繼承Exception,好處是必須要處理異常
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Springboot啟動后立即某個執(zhí)行方法的四種方式
spring項目如何在啟動項目是執(zhí)行一些操作,在spring中能通過那些操作實現(xiàn)這個功能呢,下面這篇文章主要給大家介紹了關(guān)于Springboot啟動后立即某個執(zhí)行方法的四種方式,需要的朋友可以參考下2022-06-06
java使用TimeZone將中國標(biāo)準(zhǔn)時間轉(zhuǎn)成時區(qū)值
這篇文章主要介紹了java使用TimeZone將中國標(biāo)準(zhǔn)時間轉(zhuǎn)成時區(qū)值的相關(guān)資料,需要的朋友可以參考下2023-11-11
Spring Boot 中application.yml與bootstrap.yml的區(qū)別
其實yml和properties文件是一樣的原理,且一個項目上要么yml或者properties,二選一的存在。這篇文章給大家介紹了Spring Boot 中application.yml與bootstrap.yml的區(qū)別,感興趣的朋友一起看看吧2018-04-04
java實現(xiàn)的連接oracle/mysql數(shù)據(jù)庫功能簡單示例【附oracle+mysql數(shù)據(jù)庫驅(qū)動包】
這篇文章主要介紹了java實現(xiàn)的連接oracle/mysql數(shù)據(jù)庫功能,結(jié)合實例形式分析了java基于jdbc連接Oracle與mysql的相關(guān)操作技巧,并附帶完整實例代碼與oracle+mysql數(shù)據(jù)庫驅(qū)動包供讀者下載參考,需要的朋友可以參考下2017-10-10

