57,值針對異常的情況才適用異常
在現(xiàn)代jvm上實(shí)現(xiàn)上,基于異常的模式比標(biāo)準(zhǔn)模式要慢的多醋寝。
異常只能用于異常情況下,他們永遠(yuǎn)不用改用于正常的控制流带迟。
設(shè)計(jì)良好的API不應(yīng)該強(qiáng)迫它的客戶端為了正常的控制流而適用異常音羞。
58,對可恢復(fù)的情況使用使用受檢異常仓犬,對編程錯(cuò)誤使用運(yùn)行時(shí)異常嗅绰。
java語言提供了三種可拋出結(jié)構(gòu):受檢的異常,運(yùn)行時(shí)異常和錯(cuò)誤搀继。
- 如果期望調(diào)用者能夠適當(dāng)?shù)鼗謴?fù)窘面,對于這種情況應(yīng)該使用受檢異常。
- 運(yùn)行時(shí)異常和錯(cuò)誤兩者在行為上是等同的:它們都是不需要也不應(yīng)該被捕獲的可拋出結(jié)構(gòu)叽躯。
- 用運(yùn)行時(shí)異常來表明編程錯(cuò)誤财边。大多數(shù)運(yùn)行時(shí)異常都表示前提違例,就是指沒有遵守API規(guī)范建立的約定险毁。如:數(shù)組下標(biāo)錯(cuò)誤制圈。
- 最好不要再實(shí)現(xiàn)任何新的Error子類。因此畔况,你實(shí)現(xiàn)的所有未受檢的拋出結(jié)構(gòu)都應(yīng)該是RuntimeException的子類(直接或間接的)。
例外:
考慮資源枯竭的情況慧库,這可能是程序錯(cuò)誤引起的跷跪,比如分配一塊不合理的過大的數(shù)組,也可能是資源不足引起的齐板。
因?yàn)槭軝z異常往往指明了可恢復(fù)的條件吵瞻,所以葛菇,對于這樣的異常,提供一些輔助方法尤其重要橡羞,通過這些方法眯停,調(diào)用者可以獲得一些有助于恢復(fù)的西你想。
59卿泽,避免不必要的使用受檢的異常
與返回代碼不同莺债,他們強(qiáng)迫程序員處理異常的條件,大大增強(qiáng)了可靠性签夭。也就是說使用受檢的異常會(huì)使API使用起來非常不方便齐邦。
如果正確使用API并不能阻止這中異常條件的產(chǎn)生,并且一旦產(chǎn)生異常第租,使用API的程序員可以立即采取有用過的方法措拇,這種負(fù)擔(dān)就被認(rèn)為是正當(dāng)?shù)摹?/p>
把受檢異常變成未受檢異常的一種方法是,把這個(gè)拋出異常的方法分成兩個(gè)方法慎宾,其中一個(gè)方法返回一個(gè)boolean丐吓,表明是否應(yīng)該拋出異常。
60趟据,優(yōu)先使用標(biāo)準(zhǔn)的異常
專家級程序員與缺乏經(jīng)驗(yàn)的程序員一個(gè)最主要的區(qū)別在于券犁,專家追求并且通常也能夠?qū)崿F(xiàn)高度的代碼重用。
重用現(xiàn)有的異常有多方面的好處:
- 最主要的好處是之宿,它使你的API更加易于學(xué)習(xí)和使用族操,因?yàn)樗c程序員已熟悉的習(xí)慣用法一致的。
- 對于用到這些API的程序員而言比被,他們的可讀性會(huì)更好色难,因?yàn)樗鼈儾粫?huì)出現(xiàn)很多程序員不熟悉的異常。
- 異常類越少等缀,意味著內(nèi)存印記(footparint)就越小枷莉,裝載這些類的時(shí)間開銷也越少。
在條件許可的條件下尺迂,其他的異常也可以被重用笤妙。如果某個(gè)異常能夠滿足你的需求,就不要猶豫噪裕,使用就是蹲盘,不過,一定要確保拋出異常的條件與改異常的文檔中描述的條件一致膳音。而且如果希望稍微增加更過的失敗——捕捉信息召衔,可以放心地把現(xiàn)有的異常進(jìn)行子類化。
61祭陷,拋出與抽象相對應(yīng)的異常
更高層的實(shí)現(xiàn)應(yīng)該捕獲底層的異常苍凛,同時(shí)拋出可以按照高層抽象進(jìn)行解釋的異常趣席。這種做法應(yīng)該被稱為異常轉(zhuǎn)譯。
有一種特殊的異常轉(zhuǎn)譯稱為異常鏈醇蝴,如果底層的異常對于調(diào)試導(dǎo)致高層異常的問題非常有幫助宣肚,使用異常鏈就很適合。
如果不能阻止或者處理來自更低層次的異常悠栓,一般做法是使用異常轉(zhuǎn)譯霉涨,除非低層次的方法碰巧可以保證它拋出的所有異常對高層也適合才可以將異常從底層傳播到高層。
62.每個(gè)方法拋出的異常都要有文檔
描述一個(gè)方法所拋出的異常闸迷,是正確使用這個(gè)方法時(shí)所需文檔的重要組成部分嵌纲。
- 始終要單獨(dú)聲明受檢的異常,并且利用javadoc的@throws標(biāo)記腥沽,準(zhǔn)確地記錄下來拋出的每個(gè)異常條件逮走。
- 不要使用throws關(guān)鍵字將未受檢的異常也包含在方法的聲明中。
- 如果一個(gè)類中的許多方法出于同樣的原因而拋出同一個(gè)異常今阳,在該類的文檔注釋中對這個(gè)異常建立文檔师溅,這是可以接受的。
63盾舌,在細(xì)節(jié)消息中包含能捕捉失敗的異常
為了捕捉失敗墓臭,異常的細(xì)節(jié)信息應(yīng)該包含所有“對改異常有貢獻(xiàn)”的參數(shù)和域的值。
為了確保在異常的細(xì)節(jié)消息中包含足夠的能捕捉失敗的信息妖谴,一種辦法是在異常的構(gòu)造器而不是字符串細(xì)節(jié)中引入這些信息窿锉。然后,有了這些信息膝舅,只要把它們放到消息描述中嗡载,就可以自動(dòng)產(chǎn)生細(xì)節(jié)消息。
64仍稀,努力使失敗保持原子性
當(dāng)對象拋出異常之后洼滚,通常我們希望這個(gè)對象依然保持在一種定義良好的可用狀態(tài)中,即使失敗是發(fā)生在執(zhí)行某個(gè)操作的過程中技潘。
- 最簡單的方法莫過于設(shè)計(jì)一個(gè)不可變的對象遥巴。如果對象時(shí)不可變的,失敗的原子性就是顯然的享幽。
- 對于可變對象铲掐,最常見的辦法是,在執(zhí)行前檢查參數(shù)的有效性值桩。
- 一種類似的獲得失敗原子性的方法是迹炼,調(diào)整計(jì)算處理過程的順序,使得任何可能會(huì)失敗的計(jì)算部分都在對象狀態(tài)被修改錢發(fā)生颠毙。
- 編寫一段恢復(fù)代碼斯入,由它來攔截操作過程中發(fā)生的失敗,以及對象回滾到操作開始之前的狀態(tài)上蛀蜜。這種辦法主要用于永久性的(基于磁盤的)數(shù)據(jù)結(jié)構(gòu)刻两。
- 在對象的一份臨時(shí)拷貝上執(zhí)行操作,當(dāng)操作完成之后再用臨時(shí)拷貝中的結(jié)果代替對象的內(nèi)容滴某。
如果異常發(fā)生對象沒有保持在改方法調(diào)用前磅摹,API文檔應(yīng)該清楚的指出將會(huì)處于什么狀態(tài)。
65霎奢,不要忽略異常
要忽略一個(gè)異常非常簡單户誓,只需將方法調(diào)用通過try語句包圍起來,并包含一個(gè)空的catch塊幕侠。空的catch塊會(huì)使異常達(dá)不到應(yīng)有的目的帝美。
用空catch塊忽略它,將會(huì)導(dǎo)致程序在遇到錯(cuò)誤的情況下悄然地執(zhí)行下去晤硕,然后可能在將來的某個(gè)點(diǎn)導(dǎo)致程序失敗悼潭,卻不能發(fā)現(xiàn)錯(cuò)誤在哪。
正確地處理異常能夠徹底挽回失敗舞箍。只要將異常傳播到外界舰褪,至少會(huì)導(dǎo)致程序迅速地失敗,從而保留了有助于調(diào)試該失敗條件的訊息疏橄。