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