通過異常處理錯(cuò)誤
12.1概念
“異炒赴叮”這個(gè)詞有“我對(duì)此感到意外”的意思。問題出現(xiàn)了码荔,你也許不清楚該如何處理,但你的確知道不應(yīng)該置之不理感挥;你要停下來缩搅,看看是不是有別人或在別的地方,能夠處理這個(gè)問題链快。只是在當(dāng)前的環(huán)境中還沒有足夠的信息來解決這個(gè)問題誉己,所以就把這個(gè)問題提交到一個(gè)更高級(jí)別的環(huán)境中眉尸,在這里將作出正確的決定域蜗。
使用異常所帶來的另一個(gè)相當(dāng)明顯的好處是巨双,它往往能夠降低錯(cuò)誤處理代碼的復(fù)雜度。這種方式不僅節(jié)省代碼霉祸,而且把“描述在正常執(zhí)行過程中做什么事”的代碼和“出了問題怎么辦”的代碼相分離筑累。總之丝蹭,與之前的錯(cuò)誤處理方法相比慢宗,異常機(jī)制使代碼的閱讀、編寫和調(diào)試工作更加井井有條奔穿。
12.2基本異常
異常情形是指阻止當(dāng)前方法或作用域繼續(xù)執(zhí)行的問題镜沽。你所能做的就是拋出異常,即從當(dāng)前環(huán)境跳出贱田,并且把問題提交給上一級(jí)處理缅茉。
拋出異常后,有幾件事會(huì)隨之發(fā)生男摧。首先蔬墩,將使用new在堆上創(chuàng)建異常對(duì)象。然后耗拓,當(dāng)前的執(zhí)行路徑被終止拇颅,并且從當(dāng)前環(huán)境中彈出對(duì)異常對(duì)象的引用。此時(shí)乔询,異常處理機(jī)制接管程序樟插,并開始尋找一個(gè)恰當(dāng)?shù)牡胤絹砝^續(xù)執(zhí)行程序。這個(gè)恰當(dāng)?shù)牡胤骄褪钱惓L幚沓绦蚋绻龋娜蝿?wù)是將程序從錯(cuò)誤狀態(tài)中恢復(fù)岸夯,以使程序能要么換一種方式運(yùn)行,要么繼續(xù)運(yùn)行下去们妥。
能夠拋出任意類型的Throwable對(duì)象猜扮,它是異常類型的根類。
12.3捕獲異常
try{
//code that might generate exceptions
}catch(Type1 id1){
//handle exceptions of Type1
}catch(Type2 id2){
//handle exceptions of Type2
}
12.4創(chuàng)建自定義異常
要自己定義異常類监婶,必須從已有的異常類繼承旅赢,最好是選擇意思相近的異常類繼承。
Throwable類的printStackTrace()方法將打印“從方法調(diào)用處直到異常拋出處”的方法調(diào)用序列惑惶。
12.5異常說明
異常說明使用了附加的關(guān)鍵字throws煮盼,后面接一個(gè)所有潛在異常類型的列表,示例:
void f() throws TooBig, TooSmall, DivZero{//....
12.6捕獲所有異常
可以只寫一個(gè)異常處理程序來捕獲所有類型的異常带污。通過捕獲異常類型的基類Excpetion來實(shí)現(xiàn):
catch(Exception e){//...
}
如果將異常對(duì)象重新拋出僵控,printStackTrace()方法顯示原來異常拋出點(diǎn)的調(diào)用棧信息,而非重新拋出點(diǎn)的信息鱼冀。而fillInStackTrace()可以更新這個(gè)信息报破。
通過initCause()方法可以構(gòu)造異常鏈
12.7Java標(biāo)準(zhǔn)異常
Throwable這個(gè)Java類被用來表示任何可以作為異常被拋出的類悠就。Throwable對(duì)象可分為兩種類型:Error用來表示編譯時(shí)和系統(tǒng)錯(cuò)誤;Exception是可以被拋出的基本類型充易。
其中梗脾,RuntimeException是一個(gè)特例。屬于運(yùn)行時(shí)異常盹靴,它們會(huì)自動(dòng)被Java虛擬機(jī)拋出炸茧,所以不必在異常說明中把它們列出來。被稱為“不受檢查異掣寰玻”梭冠。這種異常屬于錯(cuò)誤,將被自動(dòng)捕獲改备。
12.8使用finally進(jìn)行清理
希望無論try塊中的異常是否拋出妈嘹,finally代碼都會(huì)執(zhí)行。
finally子句用于當(dāng)要把除內(nèi)存之外的資源恢復(fù)到它們的初始狀態(tài)時(shí)绍妨,這種需要清理的資源包括:已經(jīng)打開的文件或網(wǎng)絡(luò)連接润脸,在屏幕上畫的圖形,甚至可以時(shí)外部世界的某個(gè)開關(guān)他去。
另外毙驯,在一個(gè)方法中可以從多個(gè)點(diǎn)返回(return),finally子句可以保證重要的清理仍舊會(huì)執(zhí)行灾测。
Java的異常實(shí)現(xiàn)也有瑕疵爆价,用某些特殊的方式使用finally子句,會(huì)發(fā)生異常丟失的情況:
try{
try{
//拋出了異常1
}finally{
//拋出了異常2
}
}catch(Exception e){
//...
}
該代碼只會(huì)捕獲異常2
另一種丟失異常的方式時(shí)從finally子句中返回
public class ExceptionSilencer{
public static void main(String[] args){
try{
throw new RuntimeException();
}finally{
return;
}
}
}
12.9異常的限制
當(dāng)覆蓋方法的時(shí)候媳搪,只能拋出在基類方法的異常說明里列出的那些異常铭段。
異常限制對(duì)構(gòu)造器不起作用,子類異常構(gòu)造器可以拋出任何異常秦爆,而不必理會(huì)基類構(gòu)造器所拋出的異常序愚。子類構(gòu)造器的異常說明必須包含基類構(gòu)造器的異常說明。
此外等限,一個(gè)出現(xiàn)在基類方法的異常說明中的異常爸吮,不一定會(huì)出現(xiàn)在派生類方法的異常說明里。換句話說望门,在繼承和覆蓋的過程中形娇,某個(gè)特定方法的“異常說明的接口”不是變大了而是變小了——這恰好和類接口在繼承時(shí)的情形相反。
12.10構(gòu)造器
對(duì)于在構(gòu)造階段可能會(huì)拋出異常筹误,并且要求清理的類桐早,最安全的使用方式是使用嵌套的try子句。基本規(guī)則是:在創(chuàng)建需要清理的對(duì)象后哄酝,立即進(jìn)入一個(gè)try-finally子句所灸。
12.11異常匹配
拋出異常的時(shí)候,異常處理系統(tǒng)會(huì)按照代碼的書寫順序找出“最近”的處理程序炫七。找到匹配的處理程序之后,它就認(rèn)為異常將得到處理钾唬,然后就不再繼續(xù)查找万哪。
查找的時(shí)候并不要求拋出的異常痛處理程序所聲明的異常完全匹配。派生類的對(duì)象也可以匹配其基類的處理程序抡秆。
12.12其他可選方式
待完善
12.13異常使用指南
應(yīng)該在下列情況下使用異常:
1奕巍、 在恰當(dāng)?shù)募?jí)別處理問題
2、解決問題并且重新調(diào)用產(chǎn)生異常的方法
3儒士、進(jìn)行少許修補(bǔ)的止,然后繞過異常發(fā)生的地方繼續(xù)執(zhí)行
4、用別的數(shù)據(jù)進(jìn)行計(jì)算着撩,以代替方法預(yù)計(jì)會(huì)返回的值
5诅福、把當(dāng)前運(yùn)行環(huán)境下能做的事情盡量做完,然后把相同的異常重拋到更高層拖叙。
6氓润、把當(dāng)前運(yùn)行環(huán)境下能做的事情盡量做完,然后把不同的異常重拋到更高層薯鳍。
7咖气、終止程序
8、進(jìn)行簡(jiǎn)化
9挖滤、讓類庫和程序更安全
12.14總結(jié)
異常處理的優(yōu)點(diǎn)之一就是它使得你可以在某處集中精力處理你要解決的問題崩溪,而在另一處處理你編寫的這段代碼中產(chǎn)生的錯(cuò)誤。