java 異常捕獲及處理案例詳解
一、Java異常簡介
什么是異常?
程序運(yùn)行時(shí),發(fā)生的不被期望的事件,它阻止了程序按照程序員的預(yù)期正常執(zhí)行,這就是異常。異常發(fā)生時(shí),是任程序自生自滅,立刻退出終止。在Java中即,Java在編譯或運(yùn)行或者運(yùn)行過程中出現(xiàn)的錯(cuò)誤。
Java提供了更加優(yōu)秀的解決辦法:異常處理機(jī)制。
異常處理機(jī)制能讓程序在異常發(fā)生時(shí),按照代碼的預(yù)先設(shè)定的異常處理邏輯,針對(duì)性地處理異常,讓程序盡最大可能恢復(fù)正常并繼續(xù)執(zhí)行,且保持代碼的清晰。
Java中的異??梢允呛瘮?shù)中的語句執(zhí)行時(shí)引發(fā)的,也可以是程序員通過throw 語句手動(dòng)拋出的,只要在Java程序中產(chǎn)生了異常,就會(huì)用一個(gè)對(duì)應(yīng)類型的異常對(duì)象來封裝異常,JRE就會(huì)試圖尋找異常處理程序來處理異常。
Java異常機(jī)制用到的幾個(gè)關(guān)鍵字:try、catch、finally、throw、throws。
- try -- 用于監(jiān)聽。將要被監(jiān)聽的代碼(可能拋出異常的代碼)放在try語句塊之內(nèi),當(dāng)try語句塊內(nèi)發(fā)生異常時(shí),異常就被拋出。
- catch -- 用于捕獲異常。catch用來捕獲try語句塊中發(fā)生的異常。
- finally -- finally語句塊總是會(huì)被執(zhí)行。它主要用于回收在try塊里打開的物力資源(如數(shù)據(jù)庫連接、網(wǎng)絡(luò)連接和磁盤文件)。只有finally塊,執(zhí)行完成之后,才會(huì)回來執(zhí)行try或者catch塊中的return或者throw語句,如果finally中使用了return或者throw等終止方法的語句,則就不會(huì)跳回執(zhí)行,直接停止。
- throw -- 用于拋出異常。
- throws -- 用在方法簽名中,用于聲明該方法可能拋出的異常。主方法上也可以使用throws拋出。如果在主方法上使用了throws拋出,就表示在主方法里面可以不用強(qiáng)制性進(jìn)行異常處理,如果出現(xiàn)了異常,就交給JVM進(jìn)行默認(rèn)處理,則此時(shí)會(huì)導(dǎo)致程序中斷執(zhí)行。
產(chǎn)生異常的原因:
- 用戶輸入了非法數(shù)據(jù)。
- 要打開的文件不存在。
- 網(wǎng)絡(luò)通信時(shí)連接中斷,或者JVM內(nèi)存溢出。
這些異常有的是因?yàn)橛脩翦e(cuò)誤引起,有的是程序錯(cuò)誤引起的,還有其它一些是因?yàn)槲锢礤e(cuò)誤引起的。
三種類型的異常:
- 檢查性異常:最具代表的檢查性異常是用戶錯(cuò)誤或問題引起的異常,這是程序員無法預(yù)見的。例如要打開一個(gè)不存在文件時(shí),一個(gè)異常就發(fā)生了,這些異常在編譯時(shí)不能被簡單地忽略。
- 運(yùn)行時(shí)異常: 運(yùn)行時(shí)異常是可能被程序員避免的異常。與檢查性異常相反,運(yùn)行時(shí)異??梢栽诰幾g時(shí)被忽略。
- 錯(cuò)誤: 錯(cuò)誤不是異常,而是脫離程序員控制的問題。錯(cuò)誤在代碼中通常被忽略。例如,當(dāng)棧溢出時(shí),一個(gè)錯(cuò)誤就發(fā)生了,它們?cè)诰幾g也檢查不到的。
二、Java異常的分類
異常的根接口Throwable,其下有2個(gè)子接口,Error和Exception。
- Error:指的是JVM錯(cuò)誤,這時(shí)的程序并沒有執(zhí)行,無法處理;
- Exception:指的是程序運(yùn)行中產(chǎn)生的異常,用戶可以使用處理格式處理。
Java 內(nèi)置異常類
Java 語言定義了一些異常類在 java.lang 標(biāo)準(zhǔn)包中。
標(biāo)準(zhǔn)運(yùn)行時(shí)異常類的子類是最常見的異常類。由于 java.lang 包是默認(rèn)加載到所有的 Java 程序的,所以大部分從運(yùn)行時(shí)異常類繼承而來的異常都可以直接使用。
Java 根據(jù)各個(gè)類庫也定義了一些其他的異常,下面的表中列出了 Java 的非檢查性異常。
異常 | 描述 |
---|---|
ArithmeticException | 當(dāng)出現(xiàn)異常的運(yùn)算條件時(shí),拋出此異常。例如,一個(gè)整數(shù)"除以零"時(shí),拋出此類的一個(gè)實(shí)例。 |
ArrayIndexOutOfBoundsException | 用非法索引訪問數(shù)組時(shí)拋出的異常。如果索引為負(fù)或大于等于數(shù)組大小,則該索引為非法索引。 |
ArrayStoreException | 試圖將錯(cuò)誤類型的對(duì)象存儲(chǔ)到一個(gè)對(duì)象數(shù)組時(shí)拋出的異常。 |
ClassCastException | 當(dāng)試圖將對(duì)象強(qiáng)制轉(zhuǎn)換為不是實(shí)例的子類時(shí),拋出該異常。 |
IllegalArgumentException | 拋出的異常表明向方法傳遞了一個(gè)不合法或不正確的參數(shù)。 |
IllegalMonitorStateException | 拋出的異常表明某一線程已經(jīng)試圖等待對(duì)象的監(jiān)視器,或者試圖通知其他正在等待對(duì)象的監(jiān)視器而本身沒有指定監(jiān)視器的線程。 |
IllegalStateException | 在非法或不適當(dāng)?shù)臅r(shí)間調(diào)用方法時(shí)產(chǎn)生的信號(hào)。換句話說,即 Java 環(huán)境或 Java 應(yīng)用程序沒有處于請(qǐng)求操作所要求的適當(dāng)狀態(tài)下。 |
IllegalThreadStateException | 線程沒有處于請(qǐng)求操作所要求的適當(dāng)狀態(tài)時(shí)拋出的異常。 |
IndexOutOfBoundsException | 指示某排序索引(例如對(duì)數(shù)組、字符串或向量的排序)超出范圍時(shí)拋出。 |
NegativeArraySizeException | 如果應(yīng)用程序試圖創(chuàng)建大小為負(fù)的數(shù)組,則拋出該異常。 |
NullPointerException | 當(dāng)應(yīng)用程序試圖在需要對(duì)象的地方使用 null 時(shí),拋出該異常 |
NumberFormatException | 當(dāng)應(yīng)用程序試圖將字符串轉(zhuǎn)換成一種數(shù)值類型,但該字符串不能轉(zhuǎn)換為適當(dāng)格式時(shí),拋出該異常。 |
SecurityException | 由安全管理器拋出的異常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此異常由 String 方法拋出,指示索引或者為負(fù),或者超出字符串的大小。 |
UnsupportedOperationException | 當(dāng)不支持請(qǐng)求的操作時(shí),拋出該異常。 |
下面的表中列出了 Java 定義在 java.lang 包中的檢查性異常類。
異常 | 描述 |
---|---|
ClassNotFoundException | 應(yīng)用程序試圖加載類時(shí),找不到相應(yīng)的類,拋出該異常。 |
CloneNotSupportedException | 當(dāng)調(diào)用 Object 類中的 clone 方法克隆對(duì)象,但該對(duì)象的類無法實(shí)現(xiàn) Cloneable 接口時(shí),拋出該異常。 |
IllegalAccessException | 拒絕訪問一個(gè)類的時(shí)候,拋出該異常。 |
InstantiationException | 當(dāng)試圖使用 Class 類中的 newInstance 方法創(chuàng)建一個(gè)類的實(shí)例,而指定的類對(duì)象因?yàn)槭且粋€(gè)接口或是一個(gè)抽象類而無法實(shí)例化時(shí),拋出該異常。 |
InterruptedException | 一個(gè)線程被另一個(gè)線程中斷,拋出該異常。 |
NoSuchFieldException | 請(qǐng)求的變量不存在 |
NoSuchMethodException | 請(qǐng)求的方法不存在 |
異常方法
下面的列表是 Throwable 類的主要方法:
序號(hào) | 方法及說明 |
---|---|
1 | public String getMessage() 返回關(guān)于發(fā)生的異常的詳細(xì)信息。這個(gè)消息在Throwable 類的構(gòu)造函數(shù)中初始化了。 |
2 | public Throwable getCause() 返回一個(gè)Throwable 對(duì)象代表異常原因。 |
3 | public String toString() 使用getMessage()的結(jié)果返回類的串級(jí)名字。 |
4 | public void printStackTrace() 打印toString()結(jié)果和棧層次到System.err,即錯(cuò)誤輸出流。 |
5 | public StackTraceElement [] getStackTrace() 返回一個(gè)包含堆棧層次的數(shù)組。下標(biāo)為0的元素代表?xiàng)m?,最后一個(gè)元素代表方法調(diào)用堆棧的棧底。 |
6 | public Throwable fillInStackTrace() 用當(dāng)前的調(diào)用棧層次填充Throwable 對(duì)象棧層次,添加到棧層次任何先前信息中。 |
三、異常的使用及執(zhí)行流程
1、異常的處理方案
try...catch、try...catch...finally、try...finally
try{
可能會(huì)發(fā)生的異常
}catch(異常類型 異常名(變量)){
針對(duì)異常進(jìn)行處理的代碼
}catch(異常類型 異常名(變量)){
針對(duì)異常進(jìn)行處理的代碼
}...
[finally{
釋放資源代碼;
}]
注意:
- catch 不能獨(dú)立于 try 存在。
- catch里面不能沒有內(nèi)容
- 在 try/catch 后面添加 finally 塊并非強(qiáng)制性要求的。
- try 代碼后不能既沒 catch 塊也沒 finally 塊。
- try里面越少越好。
- try, catch, finally 塊之間不能添加任何代碼。
- finally里面的代碼最終一定會(huì)執(zhí)行(除了JVM退出)
- 如果程序可能存在多個(gè)異常,需要多個(gè)catch進(jìn)行捕獲。
- 異常如果是同級(jí)關(guān)系,catch誰前誰后沒有關(guān)系
如果異常之間存在上下級(jí)關(guān)系,上級(jí)需要放在后面
2、異常的執(zhí)行流程
Error(錯(cuò)誤)是系統(tǒng)中的錯(cuò)誤,程序員是不能改變的和處理的,是在程序編譯時(shí)出現(xiàn)的錯(cuò)誤,只能通過修改程序才能修正。一般是指與虛擬機(jī)相關(guān)的問題,如系統(tǒng)崩潰,虛擬機(jī)錯(cuò)誤,內(nèi)存空間不足,方法調(diào)用棧溢等。對(duì)于這類錯(cuò)誤的導(dǎo)致的應(yīng)用程序中斷,僅靠程序本身無法恢復(fù)和和預(yù)防,遇到這樣的錯(cuò)誤,建議讓程序終止。
Exception(異常)表示程序可以處理的異常,可以捕獲且可能恢復(fù)。遇到這類異常,應(yīng)該盡可能處理異常,使程序恢復(fù)運(yùn)行,而不應(yīng)該隨意終止異常。
在catch捕獲異常時(shí),為什么不考慮使用Throwable類型,而只是使用Exception來進(jìn)行接收?
Throwable表示的范圍要比Exception大。實(shí)際上程序使用Throwable來進(jìn)行處理,沒有任何語法問題,但是卻會(huì)存在邏輯問題。因?yàn)榇藭r(shí)出現(xiàn)的(或者說用戶能夠處理的)只有Exception類型,而如果使用Throwable接收,還會(huì)表示可以處理Error的錯(cuò)誤,而用戶是處理不了Error錯(cuò)誤的,所以在開發(fā)中用戶可以處理的異常都要求以Exception類為主。
異常是一起處理好還是分開處理好?
根據(jù)實(shí)際的開發(fā)要求是否嚴(yán)格來決定。在實(shí)際的項(xiàng)目開發(fā)項(xiàng)目工作中,所有的異常是統(tǒng)一使用Exception處理還是分開處理,完全根據(jù)開發(fā)者的項(xiàng)目開發(fā)標(biāo)準(zhǔn)來決定。如果項(xiàng)目開發(fā)環(huán)境嚴(yán)謹(jǐn),基本上要求針對(duì)每一種異常分別進(jìn)行處理,并且要詳細(xì)記錄下異常產(chǎn)生的時(shí)間以及產(chǎn)生的位置,這樣可以方便程序維護(hù)人員進(jìn)行代碼的維護(hù)。再次注意:處理多個(gè)異常時(shí),捕獲范圍小的異常要放在捕獲范圍大的異常之前處理。
throw和throws的區(qū)別?
throw和throws都是在異常處理中使用的關(guān)鍵字,區(qū)別如下:
- throw:指的是在方法中人為拋出一個(gè)異常對(duì)象(這個(gè)異常對(duì)象可能是自己實(shí)例化或者拋出已存在的);
- throws:在方法的聲明上使用,表示此方法在調(diào)用時(shí)必須處理異常。
檢查型異常(Checked Exception)與非檢查型異常(Unchecked Exception)區(qū)別?
- 所有的檢查性異常都繼承自java.lang.Exception;所有的非檢查性異常都繼承自java.lang.RuntimeEx ception。
- 檢查性異常和非檢查性異常最主要的區(qū)別在于其處理異常的方式:檢查性異常必須使用try catch或者throws等關(guān)鍵字進(jìn)行處理,否則編譯器會(huì)報(bào)錯(cuò);非檢查性異常一般是程序代碼寫的不夠嚴(yán)謹(jǐn)而導(dǎo)致的問題,可以通過修改代碼來規(guī)避。
- 常見的運(yùn)行時(shí)異常:空指針異常(NullPointerException)、除零異常(ArithmeticException)、數(shù)組越界異常(ArrayIndexOutOfBoundsException)等;
- 常見的檢查性異常:輸入輸出異常(IOException)、文件不存在異常(FileNotFoundException)、SQL語句異常(SQLException)等。
assert關(guān)鍵字(了解)
在Java中,assert關(guān)鍵字是從JAVA SE 1.4 引入的,為了避免和老版本的Java代碼中使用了assert關(guān)鍵字導(dǎo)致錯(cuò)誤,Java在執(zhí)行的時(shí)候默認(rèn)是不啟動(dòng)斷言檢查的(這個(gè)時(shí)候,所有的斷言語句都 將忽略?。绻_啟斷言檢查,則需要用開關(guān)-enableassertions或-ea來開啟。
assert關(guān)鍵字語法很簡單,有兩種用法:
- assert <boolean表達(dá)式>
如果<boolean表達(dá)式>為true,則程序繼續(xù)執(zhí)行。
如果為false,則程序拋出AssertionError,并終止執(zhí)行。 - assert <boolean表達(dá)式> : <錯(cuò)誤信息表達(dá)式>
如果<boolean表達(dá)式>為true,則程序繼續(xù)執(zhí)行。
如果為false,則程序拋出java.lang.AssertionError,并輸入<錯(cuò)誤信息表達(dá)式>。
例如:
public class Test { public static void main(String[] args) { int a = 10; int b = 2; assert a == 10:"a不等于10"; System.out.println("a="+a); } }
執(zhí)行結(jié)果為:
public class Test { public static void main(String[] args) { int a = 10; int b = 2; assert a == 20:"a不等于20"; System.out.println("a="+a); } }
執(zhí)行結(jié)果為:
四、自定義異常
在 Java 中你可以自定義異常。如果要自定義異常類,則擴(kuò)展Exception類即可,因此這樣的自定義異常都屬于檢查異常(checked exception)。如果要自定義非檢查異常,則擴(kuò)展自RuntimeException。
按照國際慣例,自定義的異常應(yīng)該總是包含如下的構(gòu)造函數(shù):
- 一個(gè)無參構(gòu)造函數(shù)
- 一個(gè)帶有String參數(shù)的構(gòu)造函數(shù),并傳遞給父類的構(gòu)造函數(shù)。
- 一個(gè)帶有String參數(shù)和Throwable參數(shù),并都傳遞給父類構(gòu)造函數(shù)
- 一個(gè)帶有Throwable 參數(shù)的構(gòu)造函數(shù),并傳遞給父類的構(gòu)造函數(shù)。
下面是IOException類的完整源代碼,可以借鑒。
package java.io; public class IOException extends Exception { static final long serialVersionUID = 7818375828146090155L; public IOException() { super(); } public IOException(String message) { super(message); } public IOException(String message, Throwable cause) { super(message, cause); } public IOException(Throwable cause) { super(cause); } }
finally塊和return
- 首先一個(gè)不容易理解的事實(shí):在 try塊中即便有return,break,continue等改變執(zhí)行流的語句,finally也會(huì)執(zhí)行。
- finally中的return 會(huì)覆蓋 try 或者catch中的返回值。
- finally中的return或異常會(huì)抑制(消滅)前面try或者catch塊中的異常。
到此這篇關(guān)于java 異常捕獲及處理案例詳解的文章就介紹到這了,更多相關(guān)java 異常捕獲及處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java加密 消息摘要算法SHA實(shí)現(xiàn)詳解
這篇文章主要介紹了Java加密 消息摘要算法SHA實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07springcloud-feign調(diào)用報(bào)錯(cuò)問題
這篇文章主要介紹了springcloud-feign調(diào)用報(bào)錯(cuò)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08IDEA部署Docker鏡像的實(shí)現(xiàn)示例
本文主要介紹了IDEA部署Docker鏡像的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04mybatis入門_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了mybatis入門的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09Java?LinkedList實(shí)現(xiàn)班級(jí)信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java?LinkedList實(shí)現(xiàn)班級(jí)信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02springBoot解決static和@Component遇到的bug
這篇文章主要介紹了springBoot解決static和@Component遇到的bug,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02JDK源碼之線程并發(fā)協(xié)調(diào)神器CountDownLatch和CyclicBarrier詳解
我一直認(rèn)為程序是對(duì)于現(xiàn)實(shí)世界的邏輯描述,而在現(xiàn)實(shí)世界中很多事情都需要各方協(xié)調(diào)合作才能完成,就好比完成一個(gè)平臺(tái)的交付不可能只靠一個(gè)人,而需要研發(fā)、測(cè)試、產(chǎn)品以及項(xiàng)目經(jīng)理等不同角色人員進(jìn)行通力合作才能完成最終的交付2022-02-02