專家級(jí)程序員與缺乏經(jīng)驗(yàn)的程序員一個(gè)最重要的區(qū)別在于,專家追求并且通常也能夠?qū)崿F(xiàn)高度的代碼重用。代碼重用是值得提倡的扩然,這是一條通用的規(guī)則聋伦,異常也不例外。Java平臺(tái)類庫(kù)提供了一組基本的未受檢異常觉增,它們滿足絕大多數(shù)API的異常拋出需求兵拢。
重用標(biāo)準(zhǔn)的異常有多個(gè)好處逾礁。其中最主要的好處是说铃,它使API更易于學(xué)習(xí)和使用访惜,因?yàn)樗c程序員已經(jīng)熟悉的習(xí)慣用法一致。第二個(gè)好處是腻扇,對(duì)于用到這些API的程序而言债热,它們的可讀性會(huì)更好,因?yàn)樗鼈儾粫?huì)出現(xiàn)很多程序員不熟悉的異常幼苛。最后(也是最不重要的)一點(diǎn)是窒篱,異常類越少,意味著內(nèi)存占用就越小舶沿,裝載這些類的時(shí)間開銷也越少墙杯。
最經(jīng)常被重用的異常類型是IllegalArgumentException(詳見第49條)。當(dāng)調(diào)用者傳遞的參數(shù)值不適合的時(shí)候括荡,往往就會(huì)拋出這個(gè)異常高镐。比如,假設(shè)某一個(gè)參數(shù)代表了畸冲,“某個(gè)動(dòng)作的重復(fù)次數(shù)”避消,如果程序員給這個(gè)參數(shù)傳遞了一個(gè)負(fù)數(shù),就會(huì)拋出這個(gè)異常召夹。
另一個(gè)經(jīng)常被重用的異常是IllegalStateException岩喷。如果因?yàn)榻邮諏?duì)象的狀態(tài)而使調(diào)用非法,通常就會(huì)拋出這個(gè)異常监憎。例如纱意,如果在某個(gè)對(duì)象被正確的初始化之前,調(diào)用者就企圖使用這個(gè)對(duì)象鲸阔,就會(huì)拋出這個(gè)異常偷霉。
可以這么說,所有錯(cuò)誤的方法調(diào)用都可以被歸結(jié)為非法參數(shù)或者非法狀態(tài)褐筛,但是类少,還有一些其他的標(biāo)準(zhǔn)異常也被用于某些特定情況下的非法參數(shù)和非法狀態(tài)。如果調(diào)用者在某個(gè)不允許null值得參數(shù)中傳遞了null渔扎,習(xí)慣的做法就是拋出NullPointerException異常硫狞,而不是IllegalArgumentException。同樣的晃痴,如果調(diào)用者在表示序列下標(biāo)的參數(shù)中傳遞了越界的值残吩,應(yīng)該拋出的就是IndexOutOfBoundsException異常,而不是IllegalArgumentException倘核。
另一個(gè)值得了解的通用異常是ConcurrentModificationException泣侮。如果檢測(cè)到一個(gè)專門設(shè)計(jì)用于單線程的對(duì)象,或者與外部同步機(jī)制配合使用的對(duì)象正在(或已經(jīng))被并發(fā)的修 改紧唱,就應(yīng)該拋出這個(gè)異常活尊。這個(gè)異常頂多就是一個(gè)提示隶校,因?yàn)椴豢赡芸煽康膫蓽y(cè)到并發(fā)的修改。
最后一個(gè)值得注意的標(biāo)準(zhǔn)異常是UnsupportedOperationException蛹锰。如果對(duì)象不支持所請(qǐng)求的操作深胳,就會(huì)拋出這個(gè)異常宁仔。很少用到它翎苫,因?yàn)榻^大多數(shù)對(duì)象都會(huì)支持它們實(shí)現(xiàn)的所有方法榨了。如果類沒有實(shí)現(xiàn)由它們實(shí)現(xiàn)的接口所定義的一個(gè)或者多個(gè)可選操作,它就可以使用這個(gè)異常龙屉。例如,對(duì)于只支持追加操作的List實(shí)現(xiàn)作岖,如果視圖從列表中刪除元素五芝,他就會(huì)拋出這個(gè)異常枢步。
不要直接重用Exception、RuntimeException矾瑰、Throwable或者Error
隘擎。對(duì)待這些類要像對(duì)象抽象類一樣。你無法可靠的測(cè)試這些異常推正,因?yàn)樗鼈兪且粋€(gè)方法可能拋出的其他異常的超類宝惰。
下表概括了最常見的可重用異常:
異常 | 使用場(chǎng)合 |
---|---|
IllegalArgumentException | 非null的參數(shù)值不正確 |
IllegalStateException | 不適合方法調(diào)用的對(duì)象狀態(tài) |
NullPointerException | 在禁止使用null的情況下參數(shù)值為null |
IndexOutOfBoundsException | 下標(biāo)參數(shù)值越界 |
ConcurrentModificationException | 在禁止并發(fā)修改的情況下尼夺,檢測(cè)到對(duì)象的并發(fā)修改 |
UnsupportedOperationException | 對(duì)象不支持用戶請(qǐng)求的方法 |
雖然這些都是Java平臺(tái)類庫(kù)中迄今為止最常被重用的異常炒瘸,但是顷扩,在條件許可的情況下慰毅,其他的異常也可以被重用。例如婶芭,如果要實(shí)現(xiàn)諸如復(fù)數(shù)或者有理數(shù)之類的算術(shù)對(duì)象,也可以重用ArithmeticException和NumberFormatException犀农。如果某個(gè)異常能夠滿足你的需求呵哨,就不要猶豫轨奄,使用就是,不過一定要確保拋出的異常與該異常的文檔中描述的條件一致挪拟。這種重用必須建立在語義的基礎(chǔ)上舞丛,而不是建立在名稱的基礎(chǔ)之上。而且谷誓,如果希望稍微追加更多的失敗吨凑,捕獲信息(詳見第75條),可以放心的子類化標(biāo)準(zhǔn)異常糙臼,但要記住異常是可序列化的(詳見第12章)恩商。這也正是“如果沒有非常正當(dāng)?shù)睦碛桑f不要自己編寫異常類”的原因揽乱。
選擇重用哪一種異常并非總是那么精確,因?yàn)樯媳碇械摹笆褂脠?chǎng)合”并不是相互排斥的凰棉,比如,以表示一副紙牌的對(duì)象為例福压。假設(shè)有一個(gè)處理發(fā)牌操作的方法荆姆,它的參數(shù)是發(fā)一手牌的紙牌張數(shù)嚷那。假設(shè)調(diào)用者在這個(gè)參數(shù)中傳遞的值大于整副牌的剩余張數(shù)杆煞。這種情形既可以被解釋為IllegalArgumentException(參數(shù)的值太大),也可以被解釋為IllegalStateException(紙牌對(duì)象包含的紙牌太少)队询。在這種情況下构诚,如果沒有可用的參數(shù)值,就拋出IllegalStateException送膳,否則就拋出IllegalArgumentException
丑蛤。