9:用異常來處理錯誤
基本異常
“異常條件(exceptional condition)”是一種能阻止正在運行的方法或其某一部分繼續運行下去的問題。
異常的參數
所有的標準異常都有兩個構造函數;第一個是默認的構造函數,第二個是要拿一個字符串當參數的。
捕獲異常
“守護區域(guarded region)”是一段可能產生異常的代碼,并且后面還跟著要處理這些異常的代碼。
Try區塊
異常處理程序(exception handler)
“中止”還是“繼續”
創建你自己的異常
Thorowable類(Exception是從它那里繼承的)printStackTrace()方法會返回“被調用的方法是經過怎樣一個順序到達異常發生地點”的信息。缺省情況下,這些信息會送到標準錯誤流,但是這個方法的重載版也允許你將結果送到其他流。
對于異常類來說,getMessage()有點像toString()。
異常說明
會在編譯時進行檢查并且強制得到處理的異常被稱為checked exception.
捕捉任意類型的異常
重拋異常
fillInStackTrace(),這個方法會將當前棧的信息塞進舊的異常對象中,并返回一個Throwable對象。
異常鏈(exception chaining)
JDK 1.4中所有的Throwable的子類都有一個能接受cause(原因)對象的構造函數。這個cause就是用來保存前一個異常的。
在Throwable的子類中,只有三種基本的異常類提供了帶cause參數的構造函數,它們是Error(供JVM報告系統錯誤只用), Exception和RuntimeException。如果你要鏈接其他異常,那就不能用構造函數,而只能用initCause()方法了。
標準Java異常
RuntimeException表示編程錯誤:
1。一種你無法預料的錯誤。比如不在你控制之內的null reference。
2。一種由于“程序員忘了檢查它應該檢查的錯誤條件”而造成的錯誤(比如ArrayIndexOutOfBoundsException,你訪問數組的時候應該對數組的大小做一個檢查)。第一種情況下發生的異常,經常會演變成第二種情況下的問題。
用finally進行清理
如果你把try區放進一個循環,你就能構建一個程序運行之前必須滿足的條件了。你也可以在循環里加上static的計數器,或其它什么東西,讓它退出之前多試幾種方法。這樣你就能把程序的強壯性就能更上一個臺階。
finally是用來干什么的?
當你需要把內存以外的東西設置到原先狀態的時候,finally就顯得很有必要了。
甚至是在“異常沒有被當前這組catch子句所捕獲”的情況下,finally也會在“異常處理機制在更高一層的運行環境中開始尋找處理程序”之前得到執行。
錯誤:丟失的異常
加在異常上面的限制
派生類的構造函數不能捕獲任何由基類構造函數拋出的異常。
在繼承過程中,編譯器會對異常說明作強制要求,但異常說明本身并不屬于方法的特征(signature),特征是由方法的名字與參數的類型組成的。因此,你不能根據異常說明來重載方法。此外,一個出現在基類方法的異常說明中的異常,不一定會出現在派生類方法的異常說明里。這點同繼承的規則有明顯不同,在繼承中,基類的方法必須出現在繼承類里。換一句話說,在繼承和覆寫的過程中,方法的“異常說明的接口”不是變大而是變小了--這正好和接口在繼承時的情形相反。
構造函數
所有的清理--除了內存清理之外--都不會自動發生。
異常的匹配
其它方法
異常運用的原則
1。在合適的地方處理問題。(避免在自己還不知道該如何處理的情況下去捕捉異常)。
2。把問題解決掉,然后重新調用那個引起問題的方法。
3。修正一下問題,然后繞過那個方法再繼續下去。
4。用一些別的,不準備讓這個方法返回的數字來進行計算。
5。把當前運行環境下能作的事情全部做完,然后把相同的異常拋到更高層。
6。把當前運行環境下能做的事情全部做完,然后拋一個不同的異常到更高層。
7。中止程序。
8。簡化。(如果異常結構把事情搞得太復雜了,那用起來回事非常痛苦也很煩人)
9。把類庫和程序做得更安全。(這即使在為調試作短期投資,也是在為程序的健壯性作長期投資。)
總結:Java異常處理的目的就是要讓我們能用比現在更少的代碼,以一種更簡單的方式來開發大型,可靠的程序,并且讓你在開發過程中能更自信“你的程序里面沒有未經處理地錯誤”。異常不是特別難學,但是卻能給項目帶來立桿見影的效果。
2005年03月15日 3:31 PM