Java中的CheckedException——美麗世界中潛藏的惡魔?-編程開(kāi)發(fā)技術(shù)_第1頁(yè)
Java中的CheckedException——美麗世界中潛藏的惡魔?-編程開(kāi)發(fā)技術(shù)_第2頁(yè)
Java中的CheckedException——美麗世界中潛藏的惡魔?-編程開(kāi)發(fā)技術(shù)_第3頁(yè)
Java中的CheckedException——美麗世界中潛藏的惡魔?-編程開(kāi)發(fā)技術(shù)_第4頁(yè)
Java中的CheckedException——美麗世界中潛藏的惡魔?-編程開(kāi)發(fā)技術(shù)_第5頁(yè)
已閱讀5頁(yè),還剩5頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、java 中的 checked exception美麗世界中潛藏的惡魔?原文出處:amber-garden在使用java編寫(xiě)應(yīng)用的時(shí)候,我們常常需要通過(guò)第三方類(lèi)庫(kù)來(lái)幫助我們完成所 需要的功能。有時(shí)候這些類(lèi)庫(kù)所提供的很多api都通過(guò)throws聲明了它們所可 能拋出的異常。但是在查看這些api的文檔吋,我們卻沒(méi)有辦法找到有關(guān)這些界 常的詳盡解釋。在這種情況下,我們不能簡(jiǎn)單地忽略這些fh throws所聲明的異 常:public void shouldnotthrowcheckedexception() /該api調(diào)用可能拋出一個(gè)不明原因的checked exceptionexcept i on

2、al apt ();否則java編譯器會(huì)由于shouldnotthrowcheckedexception()函數(shù)沒(méi)冇聲明it可 能拋出的checked exception而報(bào)錯(cuò)。但是如果通過(guò)throws標(biāo)明了該函數(shù)所可 能拋ill的 checked exception,那么其它對(duì) shouldnotthrowcheckedexception () 函數(shù)的調(diào)用同樣需要通過(guò)throws標(biāo)明其可能拋出該checked exception。哦,這口j真是一件令人煩燥的事情。那我們應(yīng)該如何對(duì)這些checked exception 進(jìn)行處理呢?在木文中,我們將對(duì)如何在java應(yīng)用中使用及處理checked

3、 exception進(jìn)行簡(jiǎn)單地介紹。java異常簡(jiǎn)介在詳細(xì)介紹checked exception所導(dǎo)致的問(wèn)題之前,我們先用一小段篇幅簡(jiǎn)單介 紹一下java中的異常。在java中,異常主耍分為三種:exception, runtimcexccption以及erroro這 三類(lèi)異常都是throwable的子類(lèi)。直接從exception派生的各個(gè)異常類(lèi)型就是我 們剛剛提到的checked exceptiono它的一個(gè)比較特殊的地方就是強(qiáng)制調(diào)用方對(duì) 該異常進(jìn)行處理。就以我們常見(jiàn)的用于讀取一個(gè)文件內(nèi)容的filereader類(lèi)為例。 在該類(lèi)的構(gòu)造函數(shù)聲明中聲明了其可能會(huì)拋出fi 1 enotfoundex

4、ception:public filereader(string filename) throws filcnotfoundexccption 那么在調(diào)用該構(gòu)造函數(shù)的函數(shù)中,我們需要通過(guò)try-catch來(lái)處理該異常:public void processfile() try filereader filereader 二 new filereader (inf訂e); catch(fi1enotfoundexception exception) /異常處理邏輯如果我們不通過(guò)try-catch來(lái)處理該異常,那么我們就不得不在函數(shù)聲明中 通過(guò)throws標(biāo)明該函數(shù)會(huì)拋filenotfoundex

5、ception:public void proccssfilco throws filenotfoundexccption filereader filereader = new filereader(infile) ; / 可能拋岀 filenotfoundexception而runtimeexccption類(lèi)的各個(gè)派生類(lèi)則沒(méi)有這種強(qiáng)制調(diào)用方對(duì)異常進(jìn)行處理的 需求。為什么這兩種異常會(huì)冇如此大的區(qū)別呢?因?yàn)閞untimeexception所表示 的是軟件開(kāi)發(fā)人員沒(méi)有正確地編寫(xiě)代碼所導(dǎo)致的問(wèn)題,如數(shù)組訪問(wèn)越界等。而派 生自exception類(lèi)的各個(gè)異常所表示的并不是代碼木身的不足所導(dǎo)致的非正常

6、狀態(tài),而是一系列應(yīng)用本身也無(wú)法控制的情況。例如一個(gè)應(yīng)用在嘗試打開(kāi)一個(gè)文 件并寫(xiě)入的時(shí)候,該文件已經(jīng)被另外一個(gè)應(yīng)用打開(kāi)從而無(wú)法寫(xiě)入。對(duì)于這些情況, java通過(guò)checked exception來(lái)強(qiáng)制軟件開(kāi)發(fā)人員在編寫(xiě)代碼的時(shí)候就考慮對(duì) 這些無(wú)法避免的情況的處理,從而提高代碼質(zhì)量。而error則是一系列很難通過(guò)程序解決的問(wèn)題。這些問(wèn)題基木上是無(wú)法恢復(fù)的, 例如內(nèi)存空間不足等。在這種情況下,我們基本無(wú)法使得程序重新冋到正常軌道 上。因此一般情況下,我們不會(huì)對(duì)從e“or類(lèi)派生的齊個(gè)異常進(jìn)行處理。而且由 于其實(shí)際上與本文無(wú)關(guān),因此我們不再對(duì)其進(jìn)行詳細(xì)講解。天使變惡魔既然java小的checked ex

7、ception能夠提高用戶代碼質(zhì)量,為什么還有那么多 人反對(duì)它呢?原因很簡(jiǎn)單:它太容易被誤用了。而在本節(jié)中,我們就將列岀這些 誤用情況并提出相應(yīng)的網(wǎng)絡(luò)上最為推薦的解決方案。無(wú)處不在的throws 笫一種誤用的情況就是checked exception的廣泛傳播。在前面已經(jīng)提到過(guò),調(diào) 用一個(gè)可能拋出checked exception的api ii寸,軟件開(kāi)發(fā)人員可以有兩種選擇。 其中一種選擇就是在對(duì)該apt進(jìn)行調(diào)用的函數(shù)上添加throws聲明,并將該 checked exception 向上傳遞:public void processfile() throws filenotfoundexcep

8、tion filereader filereader = new filereader (infile) ; / 可能拋出 filenotfoundexception而在調(diào)用processfile()函數(shù)的代碼屮,軟件開(kāi)發(fā)人員可能覺(jué)得這里還不是處理 界常f訂enotfoundexception的合適地點(diǎn),因此他通過(guò)throws將該界常再次向 上傳遞。但是在一個(gè)函數(shù)上添加throws意味著其它對(duì)該函數(shù)進(jìn)行調(diào)用的代碼同 樣需耍處理該throws聲明。在一個(gè)代碼復(fù)用性比較好的系統(tǒng)中,這些throws 會(huì)非常快速地蔓延開(kāi)來(lái):從上圖中已經(jīng)口j以看出:如果不去處理checked exception,而是將

9、其通過(guò)throws 拋出,那么會(huì)有越來(lái)越多的函數(shù)受到影響。在這種情況廠我們要在多處對(duì)該 checked exception 進(jìn)行處理。如果在蔓延的過(guò)程中所遇到的是一個(gè)函數(shù)的重載或者接口的實(shí)現(xiàn),那么事情就會(huì) 變得更加麻煩了。這是因?yàn)橐粋€(gè)函數(shù)聲明中的throws實(shí)際上是函數(shù)簽名的一部 分。如果在函數(shù)重載或接口實(shí)現(xiàn)中添加了一個(gè)throws,那么為了保持原有的關(guān) 系,被重載的函數(shù)或被實(shí)現(xiàn)的接口屮的相應(yīng)函數(shù)同樣需耍添加-個(gè)throws聲明。 而這樣的改動(dòng)則會(huì)導(dǎo)致其它函數(shù)重載及接口實(shí)現(xiàn)同樣需要更改:applicationlnterface:method()b:method()c:method()d:met

10、hod()third partye:method()f:method()lnterface:method() throws xxxb:method() throws xxxc:method() throws xxxd:method() throws xxxe:method() throws xxx f:method() throws xxx在上圖中,我們顯示了在一個(gè)接口聲明中添加throws的嚴(yán)重后果。在一開(kāi)始, 我們?cè)趹?yīng)用中實(shí)現(xiàn)了接口函數(shù)interface: :method()。此時(shí)在應(yīng)用以及第三方應(yīng) 用中擁有六種對(duì)它的實(shí)現(xiàn)。但是如果a:method()的實(shí)現(xiàn)中拋出了一個(gè)checked ex

11、ception,那么其就會(huì)要求接口屮的相應(yīng)函數(shù)也添加該throws聲明。一旦在接 口中添加了 throws聲明,那么在應(yīng)用以及第三方應(yīng)用中的所有對(duì)該接口的實(shí)現(xiàn) 都需耍添加該throws聲明,即使在這些實(shí)現(xiàn)中并不存在可能拋岀該異常的函數(shù) 調(diào)用。那么我們應(yīng)該怎么解決這個(gè)問(wèn)題呢?首先,我們應(yīng)該盡早地對(duì)checked exception進(jìn)行處理。這是因?yàn)殡S著checked exception沿著函數(shù)調(diào)用的軌跡向 上傳遞的過(guò)程中,這些被拋出的checked exception的意義將逐漸模糊。例如在 startupapplication()函數(shù)屮,我們可能需要讀取用戶的配置文件來(lái)根據(jù)用戶的 原冇偏好配置

12、應(yīng)用。由于該段邏輯需要讀取用戶的配置文件,因此其內(nèi)部邏輯在 運(yùn)行時(shí)將可能拋出 filenotfoundexccptiono 如杲這個(gè) f訂cnotfoundexccption 沒(méi)冇及時(shí)地被處理,那么startupapplication()函數(shù)的簽名將如下所示:public void startupapplication() throws filenotfoundexception 在啟動(dòng)一個(gè)應(yīng)用的時(shí)候可能會(huì)產(chǎn)生一個(gè)mlenotfoundexccption異常?是的,這 很容易理解,但是到底哪里發(fā)生了異常?讀取偏好文件的時(shí)候還是加載d11的時(shí) 候?應(yīng)用或用戶需要針對(duì)該異常進(jìn)行什么樣的處理?此時(shí)我

13、們所能做的只能是 通過(guò)分析該異常實(shí)例中所記錄的信息來(lái)判斷到底哪里有異常。反過(guò)來(lái),如果我們?cè)诋a(chǎn)生checked? exception的時(shí)候立即對(duì)該異常進(jìn)行處理, 那么此時(shí)我們將擁有有關(guān)該異常的最為豐富的信息:public void readpreference() try filereader filereader = new filereader(preferencefile); catch(filenotfoundexception exception) /在日志中添加一條記錄并使用默認(rèn)設(shè)置但是在用戶那里看來(lái),他曾經(jīng)所設(shè)置的偏好在這次使用時(shí)候已經(jīng)不再有效了。這 是我們的程序在運(yùn)行時(shí)所產(chǎn)牛的異

14、常情況,因此我們需要通知用戶:因?yàn)樵瓉?lái)的 偏好文件不再存在了,因此我們將使用默認(rèn)的應(yīng)用設(shè)置。而這-切則是通過(guò)一個(gè) 在我們的應(yīng)用中定義的runtimeexception類(lèi)的派生類(lèi)來(lái)完成的:public void rcadprcfcrcncc() try filereader filereader 二 new filereader(preferencef訂e); catch(fi1enotfoundexception exception) logger log( ucould not find user prefercncc setting file: 0 ” preferencefile);th

15、row applicat ionspec i ficexcept ion(preference not found, exception);可以看到,此時(shí)在catch塊中所拋出的applicationspecificexception異常中 已經(jīng)包含了足夠多的信息。這樣,我們的應(yīng)用就可以通過(guò)捕獲applicationspecificexception來(lái)統(tǒng)一處理它們并將最為詳盡的信息顯示給用 戶,從而通知他因?yàn)闊o(wú)法找到偏好文件而使用默認(rèn)設(shè)置:try startapplication(); catch(applicationspecificexception exception) showwarn

16、ingmessage(exception. getmessage();手足無(wú)措的api使用者 另一種和checked exception相關(guān)的問(wèn)題就是對(duì)它的隨意處理。在前而的講解屮 您或許已經(jīng)知道了,如果一個(gè)checked exception不能在對(duì)api進(jìn)行調(diào)用的函數(shù) 屮被處理,那么該函數(shù)就需要添加throws聲明,從而導(dǎo)致多處代碼需要針對(duì)該 checked exception進(jìn)彳亍修改。那么好,為了避免這種情況,我們就盡早地對(duì)它 進(jìn)行處理。但是在杳看該api文檔的時(shí)候,我們卻發(fā)現(xiàn)文檔中并沒(méi)有添加任何有 關(guān)該checked exception的詳細(xì)解釋:* throws somechecke

17、dexcept ion*/public void somefunction() throws somecheckedexception 而且我們也沒(méi)有辦法從該函數(shù)的簽名屮看出到底為什么這個(gè)函數(shù)會(huì)拋出該異常, 進(jìn)而也不知道該異常是否需要對(duì)用戶可見(jiàn)。在這種情況下,我們只有截獲它并在 f1志中添加一條記錄了事:try somefunction(); catch(somecheckedexception exception) /在日志屮添加一條記錄很顯然,這并不是一種好的做法。而這一切的根本原因則是沒(méi)有說(shuō)清楚到底為什 么函數(shù)會(huì)拋岀該checked exception。因此對(duì)于一個(gè)api編寫(xiě)者而言,由于

18、throws 也是函數(shù)聲明的一部分,因此為一個(gè)函數(shù)所能拋出的checked exception添加清 晰準(zhǔn)確的文檔實(shí)際上是非常重耍的。疲于應(yīng)付的apt用戶除了沒(méi)有清晰的文檔z外,另一種讓api用戶非常抵觸的就是過(guò)度地對(duì)checked exception進(jìn)行使用。或許您已經(jīng)接觸過(guò)類(lèi)似的情況:一個(gè)類(lèi)庫(kù)中用于取得數(shù)據(jù)的api,如getdata(int index),通過(guò)throws拋出一個(gè)異常',以表示api用戶所傳入的參數(shù)index是一 個(gè)非法值。可以想象得到的是,由于getdatao可能會(huì)被非常頻繁地使用,因此 軟件開(kāi)發(fā)人員需要在每一處調(diào)用都使用trycatch塊來(lái)截獲該異常,從而 使代

19、碼顯得凌亂不堪。如果一個(gè)類(lèi)庫(kù)擁有一個(gè)這樣的api,那么該類(lèi)庫(kù)中的這種對(duì)checked exception 的不恰當(dāng)使用常常不止一個(gè)。那么該類(lèi)庫(kù)的這些api會(huì)大量地污染用戶代碼,使 得這些用戶代碼中充斥著不必要也沒(méi)有任何意義的try-catch塊,進(jìn)而讓代 碼邏輯顯得極為晦澀難懂。record record = null;try record 二 library.getdataat(2); catch(tnvalidtndexexception exception) /異常處理邏輯record. setlntvalue (record. getlntvalue() * 2);try 1ibrar

20、y. setdataat(2, record); catch(tnvalidtndexexception exception) /異常處理邏輯反過(guò)來(lái),如果這些都不是checked exception,而且軟件開(kāi)發(fā)人員也能保證傳入 的索引是合法的,那么代碼會(huì)簡(jiǎn)化很多:record record 二 1ibrary. getdataat(2);record sctlntvaluc(record gctlntvaluco * 2);library.setdataat(2, record);那么我們應(yīng)該在什么時(shí)候使用checked exception呢?就像前面所說(shuō)的,如果一 個(gè)異常所表示的并不是代碼

21、木身的不足所導(dǎo)致的非正常狀態(tài),而是一系列應(yīng)用本 身也無(wú)法控制的情況,那么我們將需要使用checked exception。就以前血所列 出的filcrcader類(lèi)的構(gòu)造函數(shù)為例:public filereader(string filename) throws filenotfoundexception該構(gòu)造函數(shù)的簽名所表示的意義實(shí)際上是:1. 必須通過(guò)傳入的參數(shù)filename來(lái)標(biāo)示需要打開(kāi)的文件2. 如果文件存在,那么該構(gòu)造函數(shù)將返回一個(gè)filereader類(lèi)的實(shí)例3. 對(duì)該構(gòu)造函數(shù)進(jìn)行使用的代碼必須處理由filename所標(biāo)示的文件不存在,進(jìn)而拋出 filenotfoundexcepti

22、on 的情況也就是說(shuō),checked exception實(shí)際上是api設(shè)計(jì)中的一部分。在調(diào)用這個(gè)api 的時(shí)候,你不得不處理目標(biāo)文件不存在的情況。而這則是由文件系統(tǒng)的自身特性 所導(dǎo)致的。而之所以checked except io n導(dǎo)致了如此多的爭(zhēng)論和誤用,更多是i大i 為我們?cè)谟卯惓_@個(gè)用來(lái)表示應(yīng)用小的運(yùn)行錯(cuò)謀這個(gè)語(yǔ)言組成來(lái)通知用戶他所 必須處理的應(yīng)用無(wú)法控制的可能情況。也就是說(shuō),其為異常賦予了新的含義,使 得界常需要表示兩個(gè)完全不和干的概念。而在沒(méi)有仔細(xì)分辨的情況下,這兩個(gè)概 念是極容易混淆的。因此在嘗試著定義一個(gè)checked exception之前,apt編寫(xiě) 者首先要考慮這個(gè)異常所表

23、示的到底是系統(tǒng)自身缺陷所導(dǎo)致的運(yùn)行錯(cuò)誤,還是要 讓用戶自己來(lái)處理的邊緣情況。正確地使用 checked? exception 實(shí)際上,如何正確地使用checked exception已經(jīng)在前而的各章節(jié)講解屮進(jìn)行了 詳細(xì)地說(shuō)明。在這里我們?cè)俅巫鲆粋€(gè)總結(jié),同時(shí)也用來(lái)加深一下卬彖。從apt編寫(xiě)者的角度來(lái)講,他所需耍考慮的就是在何時(shí)使用一個(gè)checked exception。首先,checked exception應(yīng)當(dāng)只在異常情況對(duì)于api以及api的使用者都無(wú)法 避免的情況下被使用。例如在打開(kāi)一個(gè)文件的時(shí)候,api以及api的使用者都沒(méi) 有辦法保證該文件一定存在。反過(guò)來(lái),在通過(guò)索引訪問(wèn)數(shù)據(jù)的時(shí)候,如

24、果api 的使用者對(duì)參數(shù)index傳入的是-1,那么這就是一個(gè)代碼上的錯(cuò)誤,是完全可以 避免的。因此對(duì)于index參數(shù)值不對(duì)的情況,我們應(yīng)該使用unchecked exccptiono其次,checked exception不應(yīng)該被廣泛調(diào)用的api所拋出。這一方而是基于代 碼整潔性的考慮,另一方面則是因?yàn)閏hecked exception本身的實(shí)際意義是api 以及api的使用者都無(wú)法避免的情況。如果一個(gè)應(yīng)用有太多處這種“無(wú)法避免的 異常”,那么這個(gè)程序是否擁冇足夠的質(zhì)量也是一個(gè)很值得考慮的問(wèn)題。而就 api提供者而言,在一個(gè)主要的被廣泛使用的功能上拋出這種異常,也是對(duì)其門(mén) 身api的一種否定

25、。再次,一個(gè)checked exception應(yīng)該有明確的意義。這種明確意義的標(biāo)準(zhǔn)則是需 耍訃api使用者能夠看到這個(gè)checked exception所對(duì)應(yīng)的異常類(lèi),該異常類(lèi)所 包含的各個(gè)域,并閱讀相應(yīng)的api文檔以后就能夠了解到底哪里出現(xiàn)了問(wèn)題,進(jìn) 而向用戶提供準(zhǔn)確的有關(guān)該異常的解釋。而對(duì)于api的用戶而言,一旦遇到了一個(gè)api會(huì)拋出checked exception,那么 他就需要考慮使用一個(gè)wrapped exception來(lái)將該checked exception包裝起來(lái)。 那什么是 wrapped exception 呢?簡(jiǎn)單地說(shuō),wrapped exception就是將一個(gè)異常包裝起來(lái)的異常。在trycatch 塊捕獲到一個(gè)異常的時(shí)候,該異常內(nèi)部所記錄的消息可能并不合適。就以前面我 們已經(jīng)舉過(guò)的加載偏好的示例為例。在啟動(dòng)時(shí),應(yīng)用會(huì)嘗試讀取用戶的偏好設(shè)置。 這些偏好設(shè)置記錄在了一個(gè)文件中,卻可能已經(jīng)被誤刪除。在這種情況下,對(duì)該 偏好文件的讀取會(huì)導(dǎo)致一個(gè)filenotfoundexception拋出。但是在該異常屮所記 錄的信息對(duì)于用戶,甚至應(yīng)用編寫(xiě)者

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論