http://lavasoft.blog.51cto.com/62575/18920/
Java對(duì)異常進(jìn)行了分類,不同類型的異常分別用不同的Java類表示,所有異常的根類為java.lang.Throwable,Throwable下面又派生了兩個(gè)子類:Error和Exception,Error 表示應(yīng)用程序本身無法克服和恢復(fù)的一種嚴(yán)重問題,程序只有死的份了,例如,說內(nèi)存溢出和線程死鎖等系統(tǒng)問題。Exception表示程序還能夠克服和恢復(fù)的問題,其中又分為系統(tǒng)異常和普通異常,系統(tǒng)異常是軟件本身缺陷所導(dǎo)致的問題,也就是軟件開發(fā)人員考慮不周所導(dǎo)致的問題,軟件使用者無法克服和恢復(fù)這種問題,但在這種問題下還可以讓軟件系統(tǒng)繼續(xù)運(yùn)行或者讓軟件死掉,例如,數(shù)組腳本越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類轉(zhuǎn)換異常(ClassCastException);普通異常是運(yùn)行環(huán)境的變化或異常所導(dǎo)致的問題,是用戶能夠克服的問題,例如,網(wǎng)絡(luò)斷線,硬盤空間不夠,發(fā)生這樣的異常后,程序不應(yīng)該死掉。
java為系統(tǒng)異常和普通異常提供了不同的解決方案,編譯器強(qiáng)制普通異常必須try..catch處理或用throws聲明繼續(xù)拋給上層調(diào)用方法處理,所以普通異常也稱為checked異常,而系統(tǒng)異常可以處理也可以不處理,所以,編譯器不強(qiáng)制用try..catch處理或用throws聲明,所以系統(tǒng)異常也稱為unchecked異常。
Java異常處理通過5個(gè)關(guān)鍵字try、catch、throw、throws、finally進(jìn)行管理。基本過程是用try語(yǔ)句塊包住要監(jiān)視的語(yǔ)句,如果在try語(yǔ)句塊內(nèi)出現(xiàn)異常,則異常會(huì)被拋出,你的代碼在catch語(yǔ)句塊中可以捕獲到這個(gè)異常并做處理;還有以部分系統(tǒng)生成的異常在Java運(yùn)行時(shí)自動(dòng)拋出。你也可以通過throws關(guān)鍵字在方法上聲明該方法要拋出異常,然后在方法內(nèi)部通過throw拋出異常對(duì)象。finally語(yǔ)句塊會(huì)在方法執(zhí)行return之前執(zhí)行,一般結(jié)構(gòu)如下:
try{
程序代碼
}catch(異常類型1 異常的變量名1){
程序代碼
}catch(異常類型2 異常的變量名2){
程序代碼
}finally{
程序代碼
}
程序代碼
}catch(異常類型1 異常的變量名1){
程序代碼
}catch(異常類型2 異常的變量名2){
程序代碼
}finally{
程序代碼
}
catch語(yǔ)句可以有多個(gè),用來匹配多個(gè)異常,匹配上多個(gè)中一個(gè)后,執(zhí)行catch語(yǔ)句塊時(shí)候僅僅執(zhí)行匹配上的異常。catch的類型是Java語(yǔ)言中定義的或者程序員自己定義的,表示代碼拋出異常的類型,異常的變量名表示拋出異常的對(duì)象的引用,如果catch捕獲并匹配上了該異常,那么就可以直接用這個(gè)異常變量名,此時(shí)該異常變量名指向所匹配的異常,并且在catch代碼塊中可以直接引用。這一點(diǎn)非常非常的特殊和重要!
Java異常處理的目的是提高程序的健壯性,你可以在catch和finally代碼塊中給程序一個(gè)修正機(jī)會(huì),使得程序不因異常而終止或者流程發(fā)生以外的改變。同時(shí),通過獲取Java異常信息,也為程序的開發(fā)維護(hù)提供了方便,一般通過異常信息就很快就能找到出現(xiàn)異常的問題(代碼)所在。
Java異常處理是Java語(yǔ)言的一大特色,也是個(gè)難點(diǎn),掌握異常處理可以讓寫的代碼更健壯和易于維護(hù)。
下面是這幾個(gè)類的層次圖:
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException
java.lang.Error
java.lang.ThreadDeath
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException
java.lang.Error
java.lang.ThreadDeath
下面四個(gè)類的介紹來自java api 文檔。
1、Throwable
Throwable 類是 Java 語(yǔ)言中所有錯(cuò)誤或異常的超類。只有當(dāng)對(duì)象是此類(或其子類之一)的實(shí)例時(shí),才能通過 Java 虛擬機(jī)或者 Java throw 語(yǔ)句拋出。類似地,只有此類或其子類之一才可以是 catch 子句中的參數(shù)類型。
Throwable 類是 Java 語(yǔ)言中所有錯(cuò)誤或異常的超類。只有當(dāng)對(duì)象是此類(或其子類之一)的實(shí)例時(shí),才能通過 Java 虛擬機(jī)或者 Java throw 語(yǔ)句拋出。類似地,只有此類或其子類之一才可以是 catch 子句中的參數(shù)類型。
兩個(gè)子類的實(shí)例,Error 和 Exception,通常用于指示發(fā)生了異常情況。通常,這些實(shí)例是在異常情況的上下文中新近創(chuàng)建的,因此包含了相關(guān)的信息(比如堆棧跟蹤數(shù)據(jù))。
2、Exception
Exception 類及其子類是 Throwable 的一種形式,它指出了合理的應(yīng)用程序想要捕獲的條件,表示程序本身可以處理的異常。
Exception 類及其子類是 Throwable 的一種形式,它指出了合理的應(yīng)用程序想要捕獲的條件,表示程序本身可以處理的異常。
3、Error
Error 是 Throwable 的子類,表示僅靠程序本身無法恢復(fù)的嚴(yán)重錯(cuò)誤,用于指示合理的應(yīng)用程序不應(yīng)該試圖捕獲的嚴(yán)重問題。
Error 是 Throwable 的子類,表示僅靠程序本身無法恢復(fù)的嚴(yán)重錯(cuò)誤,用于指示合理的應(yīng)用程序不應(yīng)該試圖捕獲的嚴(yán)重問題。
在執(zhí)行該方法期間,無需在方法中通過throws聲明可能拋出但沒有捕獲的 Error 的任何子類,因?yàn)镴ava編譯器不去檢查它,也就是說,當(dāng)程序中可能出現(xiàn)這類異常時(shí),即使沒有用try...catch語(yǔ)句捕獲它,也沒有用throws字句聲明拋出它,還是會(huì)編譯通過。
4、RuntimeException
RuntimeException 是那些可能在 Java 虛擬機(jī)正常運(yùn)行期間拋出的異常的超類。Java編譯器不去檢查它,也就是說,當(dāng)程序中可能出現(xiàn)這類異常時(shí),即使沒有用try...catch語(yǔ)句捕獲它,也沒有用throws字句聲明拋出它,還是會(huì)編譯通過,這種異常可以通過改進(jìn)代碼實(shí)現(xiàn)來避免。
RuntimeException 是那些可能在 Java 虛擬機(jī)正常運(yùn)行期間拋出的異常的超類。Java編譯器不去檢查它,也就是說,當(dāng)程序中可能出現(xiàn)這類異常時(shí),即使沒有用try...catch語(yǔ)句捕獲它,也沒有用throws字句聲明拋出它,還是會(huì)編譯通過,這種異常可以通過改進(jìn)代碼實(shí)現(xiàn)來避免。
5、ThreadDeath
調(diào)用 Thread 類中帶有零參數(shù)的 stop 方法時(shí),受害線程將拋出一個(gè) ThreadDeath 實(shí)例。
調(diào)用 Thread 類中帶有零參數(shù)的 stop 方法時(shí),受害線程將拋出一個(gè) ThreadDeath 實(shí)例。
僅當(dāng)應(yīng)用程序在被異步終止后必須清除時(shí)才應(yīng)該捕獲這個(gè)類的實(shí)例。如果 ThreadDeath 被一個(gè)方法捕獲,那么將它重新拋出非常重要,因?yàn)檫@樣才能讓該線程真正終止。
如果沒有捕獲 ThreadDeath,則頂級(jí)錯(cuò)誤處理程序不會(huì)輸出消息。
雖然 ThreadDeath 類是“正常出現(xiàn)”的,但它只能是 Error 的子類而不是 Exception 的子類,因?yàn)樵S多應(yīng)用程序捕獲所有出現(xiàn)的 Exception,然后又將其放棄。
對(duì)于可能出現(xiàn)異常的代碼,有兩種處理辦法:
第一、在方法中用try...catch語(yǔ)句捕獲并處理異常,catach語(yǔ)句可以有多個(gè),用來匹配多個(gè)異常。例如:
public void p(int x){
try{
...
}catch(Exception e){
...
}finally{
...
}
}
第一、在方法中用try...catch語(yǔ)句捕獲并處理異常,catach語(yǔ)句可以有多個(gè),用來匹配多個(gè)異常。例如:
public void p(int x){
try{
...
}catch(Exception e){
...
}finally{
...
}
}
第二、對(duì)于處理不了的異常或者要轉(zhuǎn)型的異常,在方法的聲明處通過throws語(yǔ)句拋出異常。例如:
public void test1() throws MyException{
...
if(....){
throw new MyException();
}
}
...
if(....){
throw new MyException();
}
}
如果每個(gè)方法都是簡(jiǎn)單的拋出異常,那么在方法調(diào)用方法的多層嵌套調(diào)用中,Java虛擬機(jī)會(huì)從出現(xiàn)異常的方法代碼塊中往回找,直到找到處理該異常的代碼塊為止。然后將異常交給相應(yīng)的catch語(yǔ)句處理。如果Java虛擬機(jī)追溯到方法調(diào)用棧最底部main()方法時(shí),如果仍然沒有找到處理異常的代碼塊,將按照下面的步驟處理:
第一、調(diào)用異常的對(duì)象的printStackTrace()方法,打印方法調(diào)用棧的異常信息。
第二、如果出現(xiàn)異常的線程為主線程,則整個(gè)程序運(yùn)行終止;如果非主線程,則終止該線程,其他線程繼續(xù)運(yùn)行。
第一、調(diào)用異常的對(duì)象的printStackTrace()方法,打印方法調(diào)用棧的異常信息。
第二、如果出現(xiàn)異常的線程為主線程,則整個(gè)程序運(yùn)行終止;如果非主線程,則終止該線程,其他線程繼續(xù)運(yùn)行。
通過分析思考可以看出,越早處理異常消耗的資源和時(shí)間越小,產(chǎn)生影響的范圍也越小。因此,不要把自己能處理的異常也拋給調(diào)用者。
還有一點(diǎn),不可忽視:finally語(yǔ)句在任何情況下都必須執(zhí)行的代碼,這樣可以保證一些在任何情況下都必須執(zhí)行代碼的可靠性。比如,在數(shù)據(jù)庫(kù)查詢異常的時(shí)候,應(yīng)該釋放JDBC連接等等。finally語(yǔ)句先于return語(yǔ)句執(zhí)行,而不論其先后位置,也不管是否try塊出現(xiàn)異常。finally語(yǔ)句唯一不被執(zhí)行的情況是方法執(zhí)行了System.exit()方法。System.exit()的作用是終止當(dāng)前正在運(yùn)行的 Java 虛擬機(jī)。finally語(yǔ)句塊中不能通過給變量賦新值來改變r(jià)eturn的返回值,也建議不要在finally塊中使用return語(yǔ)句,沒有意義還容易導(dǎo)致錯(cuò)誤。
最后還應(yīng)該注意一下異常處理的語(yǔ)法規(guī)則:
第一、try語(yǔ)句不能單獨(dú)存在,可以和catch、finally組成 try...catch...finally、try...catch、try...finally三種結(jié)構(gòu),catch語(yǔ)句可以有一個(gè)或多個(gè),finally語(yǔ)句最多一個(gè),try、catch、finally這三個(gè)關(guān)鍵字均不能單獨(dú)使用。
第一、try語(yǔ)句不能單獨(dú)存在,可以和catch、finally組成 try...catch...finally、try...catch、try...finally三種結(jié)構(gòu),catch語(yǔ)句可以有一個(gè)或多個(gè),finally語(yǔ)句最多一個(gè),try、catch、finally這三個(gè)關(guān)鍵字均不能單獨(dú)使用。
第二、try、catch、finally三個(gè)代碼塊中變量的作用域分別獨(dú)立而不能相互訪問。如果要在三個(gè)塊中都可以訪問,則需要將變量定義到這些塊的外面。
第三、多個(gè)catch塊時(shí)候,Java虛擬機(jī)會(huì)匹配其中一個(gè)異常類或其子類,就執(zhí)行這個(gè)catch塊,而不會(huì)再執(zhí)行別的catch塊。
第四、throw語(yǔ)句后不允許有緊跟其他語(yǔ)句,因?yàn)檫@些沒有機(jī)會(huì)執(zhí)行。
第五、如果一個(gè)方法調(diào)用了另外一個(gè)聲明拋出異常的方法,那么這個(gè)方法要么處理異常,要么聲明拋出。
那怎么判斷一個(gè)方法可能會(huì)出現(xiàn)異常呢?一般來說,方法聲明的時(shí)候用了throws語(yǔ)句,方法中有throw語(yǔ)句,方法調(diào)用的方法聲明有throws關(guān)鍵字。
throw和throws關(guān)鍵字的區(qū)別
throw用來拋出一個(gè)異常,在方法體內(nèi)。語(yǔ)法格式為:throw 異常對(duì)象。
throws用來聲明方法可能會(huì)拋出什么異常,在方法名后,語(yǔ)法格式為:throws 異常類型1,異常類型2...異常類型n。
throw用來拋出一個(gè)異常,在方法體內(nèi)。語(yǔ)法格式為:throw 異常對(duì)象。
throws用來聲明方法可能會(huì)拋出什么異常,在方法名后,語(yǔ)法格式為:throws 異常類型1,異常類型2...異常類型n。