Java?Exception異常全方面分析
如下實(shí)例:
public class Demo { public static void main(String[] args) { int num = 2/0; } }
這段代碼中“除0”的邏輯在C語(yǔ)言中就只是報(bào)個(gè)警告,但是Java是比較安全的語(yǔ)言,在編譯運(yùn)行的時(shí)候會(huì)直接拋出異常
那么到底什么是異常?
一、什么是異常?
異常指的是在程序運(yùn)行過程中發(fā)生的異常事件,通常是由外部問題(如硬件錯(cuò)誤、輸入錯(cuò)誤)所導(dǎo)致的。在Java等面向?qū)ο蟮木幊陶Z(yǔ)言中異常屬于對(duì)象.
異常本身是一個(gè)對(duì)象,產(chǎn)生異常就是產(chǎn)生了一個(gè)異常對(duì)象
Java的異常體系
我們都知道Java中所有類都是繼承自O(shè)bject的,Throwable這個(gè)類也是如此,如下Java官方文檔
我們可以看到
繼承于throwable類的有兩個(gè),一個(gè)是Error(錯(cuò)誤),一個(gè)是Exception(異常),throwable是Java中所有錯(cuò)誤和異常的父類
而異常又分為受查異常和非受查異常(我們之前碰到過的除0發(fā)生的異常就是非受查異常)
非受查異常:Java語(yǔ)言規(guī)范將派生于 Error 類或 RuntimeException 類的所有異常稱為非受查異常(因?yàn)槌绦虻拇aBug導(dǎo)致的問題,空指針異常,數(shù)組下標(biāo)越界異常)
受查異常:所有的其他異常稱為 受查異常(程序編譯時(shí)拋出的異常),必須處理,否則代碼編譯不能通過(一些可以經(jīng)過重試或者程序自動(dòng)修復(fù)可以解決的問題)
錯(cuò)誤:因?yàn)樵O(shè)備或其他硬性環(huán)境導(dǎo)致的,程序根本無(wú)法修復(fù)的問題
如何排查異常
如下代碼:
在文章開頭寫的一個(gè)"除0"代碼的運(yùn)行結(jié)果:
這里面java.lang.ArithmeticException是異常的種類,by zero是異常的具體信息
常見的異常種類有:
NullPointerException:空指針異常
ArithmeticException:算術(shù)異常
ArrayIndexOutOfBoundsException:數(shù)組下標(biāo)越界異常
PS:異常的種類有很多,不同的異常具有不同的含義,也有不同的處理方式
有的時(shí)候異常信息會(huì)有很多行,這些異常信息被稱為異常信息棧/異常跟蹤棧,那么我們?nèi)绾卧谶@些異常信息中找到引發(fā)異常的第一現(xiàn)場(chǎng)呢?
直接點(diǎn)擊最上面第一條異常信息的藍(lán)色部分,光標(biāo)就會(huì)自動(dòng)跳轉(zhuǎn)到引發(fā)異常的地方,從而進(jìn)行相應(yīng)的修改
二、 處理異常
Java當(dāng)中異常的核心思想其實(shí)就是讓我們先操作,在操作過程中遇到問題再處理
try…catch基本語(yǔ)法
try{
有可能出現(xiàn)異常的語(yǔ)句;
}[catch (異常類型 異常對(duì)象) {
捕捉try當(dāng)中可能出現(xiàn)的異常;
可以寫多個(gè)catch;
} ... ]
[finally {
異常的出口;
可以不寫;
finally中的代碼一定會(huì)被執(zhí)行,用來(lái)做一些善后工作;
}]
- try 代碼塊中放的是可能出現(xiàn)異常的代碼.
- catch 代碼塊中放的是出現(xiàn)異常后的處理行為
- finally 代碼塊中的代碼用于處理善后工作, 會(huì)在最后執(zhí)行.
- 其中 catch 和 finally 都可以根據(jù)情況選擇加或者不加.
我們還是以"除0"問題為例
public static void main(String[] args) { int a = 10/0; System.out.println("666"); }
這個(gè)程序顯然到了int a = 10/0;
就會(huì)拋出異常,后面的666
不會(huì)被打印出來(lái)
此處發(fā)生異常,程序會(huì)直接交給JVM處理異常,導(dǎo)致的結(jié)果是程序會(huì)立即停止,不再向下執(zhí)行
那么我們?nèi)绻胍尦绦蚶^續(xù)往下執(zhí)行呢?
這個(gè)時(shí)候就要處理異常
public static void main(String[] args) { try { int a = 10 / 0; } catch (ArithmeticException e) { e.printStackTrace(); } System.out.println("666"); }
在try中放入可能會(huì)引發(fā)異常的語(yǔ)句,在catch后面的圓括號(hào)內(nèi)寫入想要捕獲異常的種類ArithmeticException
,然后就可以對(duì)此異常做出處理,e.printStackTrace();打印異常追蹤棧,最后再打印666
運(yùn)行結(jié)果:
當(dāng)程序拋出異常的時(shí)候,由catch塊進(jìn)行捕獲,程序自己來(lái)處理異常,導(dǎo)致的結(jié)果就是程序會(huì)繼續(xù)向下執(zhí)行
注意:如果catch中要捕獲的異常種類和實(shí)際發(fā)生異常的種類不一樣的話,就還是交給JVM處理了,程序立即停止
如果我們用Exception來(lái)捕獲異常呢?
如下代碼
public static void main(String[] args) { try { int a = 10 / 0; }catch (Exception e) { System.out.println(999); }catch (ArithmeticException e) { System.out.println(888); } // 直接捕獲Exception的話,后面的這些catch就沒啥用了,編譯器就會(huì)報(bào)錯(cuò) System.out.println("666"); }
所有異常繼承于Exception,那么當(dāng)出現(xiàn)異常的時(shí)候,Exception可以捕獲所有的異常,這樣只需要寫一個(gè)捕獲Exception的catch就行了,但是不建議這么寫,這樣得不到具體的異常種類
finally
無(wú)論catch有沒有捕獲到異常,finally塊中的代碼都會(huì)在最后被執(zhí)行
public static void main(String[] args) { try { int a = 10 / 0; System.out.println("666"); }catch (ArithmeticException e) { System.out.println("888"); }finally { System.out.println("999"); } System.out.println("777"); }
在方法中出現(xiàn)異常
如果本方法中沒有合適的處理異常的方式,就會(huì)沿著調(diào)用棧向上傳遞
public class ExceptionLearning { public static void demo() { int a = 10/0; } public static void main(String[] args) { demo(); } }
運(yùn)行結(jié)果:
在demo方法中執(zhí)行時(shí),拋出算術(shù)異常,因?yàn)閐emo方法是被main方法調(diào)用的,所以demo就會(huì)讓main方法來(lái)處理異常,但是main方法中也沒有處理異常,就會(huì)交給JVM來(lái)處理,程序就會(huì)異常終止
若對(duì)異常做出處理
public class ExceptionLearning { public static void demo() { int a = 10/0; } public static void main(String[] args) { try { demo(); }catch (ArithmeticException e) { e.printStackTrace(); }finally { System.out.println("繼續(xù)向下執(zhí)行"); } } }
在demo方法中執(zhí)行時(shí),拋出算術(shù)異常,因?yàn)閐emo方法是被main方法調(diào)用的,所以demo就會(huì)讓main方法來(lái)處理異常,main方法中對(duì)異常做出處理,程序繼續(xù)向下執(zhí)行
異常處理流程
- 程序先執(zhí)行 try 中的代碼,如果 try 中的代碼出現(xiàn)異常, 就會(huì)結(jié)束 try 中的代碼, 看和 catch 中的異常類型是否匹配.
- 如果找到匹配的異常類型, 就會(huì)執(zhí)行 catch 中的代碼,如果沒有找到匹配的異常類型, 就會(huì)將異常向上傳遞到上層調(diào)用者.
- 無(wú)論是否找到匹配的異常類型, finally 中的代碼都會(huì)被執(zhí)行到(在該方法結(jié)束之前執(zhí)行).
- 如果上層調(diào)用者也沒有處理異常, 就繼續(xù)向上傳遞,一直到 main 方法也沒有合適的代碼處理異常, 就會(huì)交給 JVM 來(lái)進(jìn)行處理, 此時(shí)程序就會(huì)異常終止
手動(dòng)拋出異常
除了Java編譯器來(lái)拋出異常以外,我們也可以自己針對(duì)一些情況來(lái)拋出異常
三、自定義異常
要知道,異常本身就是一個(gè)對(duì)象,它肯定是對(duì)應(yīng)一個(gè)類的,那么我們也可以通過創(chuàng)建類的方式來(lái)自定義異常
源碼剖析
我們這里以Arithmetic類為例,可以先看看它的源碼
從源碼中會(huì)發(fā)現(xiàn)Arithmetic這個(gè)類繼承自RuntimeException類,并且有兩個(gè)構(gòu)造方法,一個(gè)有參,一個(gè)無(wú)參
自定義
我們也可以仿照Arithmetic來(lái)自定義,如下代碼
class MyException extends RuntimeException{ public MyException() { super(); } public MyException(String str) { super(str); } } public class ExceptionLearning { public static void main(String[] args) throws MyException{ //在方法上加上異常說明, 相當(dāng)于將處理動(dòng)作交給上級(jí)調(diào)用者 int b = 0; if (b == 0) { throw new MyException("b == 0"); } } }
運(yùn)行結(jié)果
注意
當(dāng)我們將MyException
繼承于RuntimeException的時(shí)候,這個(gè)異常就默認(rèn)是非受查異常;繼承于Exception的時(shí)候,這個(gè)異常就默認(rèn)是受查異常
Java針對(duì)受查異常,強(qiáng)制要求: 一個(gè)方法如果拋出了受查異常,則必須通過throws聲明異常;如果拋出了非受查異常,則必須聲明
到此這篇關(guān)于Java Exception異常全方面分析的文章就介紹到這了,更多相關(guān)Java 異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
maven如何動(dòng)態(tài)統(tǒng)一修改版本號(hào)的方法步驟
這篇文章主要介紹了maven如何動(dòng)態(tài)統(tǒng)一修改版本號(hào)的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12Java的可變參數(shù)與Collections類的功能示例解析
這篇文章主要為大家介紹了Java的可變參數(shù)與Collections類的功能示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05Mybatis詳細(xì)對(duì)比一級(jí)緩存與二級(jí)緩存
MyBatis 包含一個(gè)非常強(qiáng)大的查詢緩存特性,它可以非常方便地配置和定制,緩存可以極大的提升查詢效率。MyBatis中默認(rèn)定義了兩級(jí)緩存,分別是一級(jí)緩存和二級(jí)緩存2022-10-10Java中使用增強(qiáng)for循環(huán)的實(shí)例方法
在本篇文章里小編給大家整理是的關(guān)于Java中如何使用增強(qiáng)for循環(huán)的實(shí)例內(nèi)容以及相關(guān)代碼,需要的朋友們可以學(xué)習(xí)下。2019-08-08java IO流 之 輸入流 InputString()的使用
這篇文章主要介紹了java IO流 之 輸入流 InputString()的使用,以及讀取數(shù)據(jù)的三種方式詳解,非常不錯(cuò),需要的朋友可以參考下2016-12-12解決eclipse中maven引用不到已經(jīng)存在maven中jar包的問題
這篇文章主要介紹了解決eclipse中maven引用不到已經(jīng)存在maven中jar包的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-10-10Springboot靜態(tài)資源訪問實(shí)現(xiàn)代碼解析
這篇文章主要介紹了Springboot靜態(tài)資源訪問實(shí)現(xiàn)代碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06使用maven-assembly-plugin如何打包多模塊項(xiàng)目
這篇文章主要介紹了使用maven-assembly-plugin如何打包多模塊項(xiàng)目,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03