亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Effective Java讀書筆記五:異常

2019-11-11 04:05:30
字體:
來源:轉載
供稿:網友

第57條:只針對異常的情況才使用異常

異常是為了在異常情況下使用而設計的,不要將它們用于普通的控制流,也不要編寫迫使它們這么做的API。

下面部分來自:異常

如果finally塊中出現了異常沒有捕獲或者是捕獲后重新拋出,則會覆蓋掉try或catch里拋出的異常,最終拋出的異常是finally塊中產生的異常,而不是try或catch塊里的異常,最后會丟失最原始的異常。

如果在try、catch、finally塊中都拋出了異常,只是只有一個異常可被傳播到外界。記住,最后被拋出的異常是唯一被調用端接受到的異常,其他異常都被掩蓋而后丟失掉了。如果調用端需要知道造成失幾的初始原因,程序之中就絕不能掩蓋任何異常。

請不要在try塊中發出對return、break或continue的調用,萬一無法避免,一定要確保finally的存在不會改變函數的返回值(比如說拋異常啊、return啊以及其他任何引起程序退出的調用)。因為那樣會引起流程混亂或返回值不確定,如果有返回值最好在try與finally外返回。

不要將try/catch放在循環內,那樣會減慢代碼的執行速度。

如果構造器調用的代碼需要拋出異常,就不要在構造器處理它,而是直接在構造器聲明上throws出來,這樣更簡潔與安全。因為如果在構造器里處理異?;驅a生異常的代碼放在構造器之外調用,都將會需要調用額外的方法來判斷構造的對象是否有效,這樣可能忘記調用這些額外的檢查而不安全。

第58條:對可恢復的情況使用受檢異常,對編程錯誤使用運用時異常

java程序設計語言提供了三種異常:受檢的異常(checked exception)、運行時異常(run-time exception)和錯誤(error)。關于什么時候適合使用哪種異常,雖然沒有明確的規定,但還是有些一般性的原則的。

檢測性異常通常是由外部條件不滿足而引起的,只要條件滿足,程序是可以正常運行的,即可在不修改程序的前提下就可正常運行;而運行時異常則是由于系統內部或編程時人為的疏忽而引起的,這種異常一定要修正錯誤代碼后再能正確運行。受檢異常對客戶是有用的,而運行時異常則是讓開發人員來調試的,對客戶沒有多大的用處。

在決定使用受檢異常還是未受檢異常時,主要的原則是:如果期望調用者能夠適當地恢復,對于這種情況就應該使用受檢的異常。拋出的受檢異常都是對API用戶的一種潛在的指示:與異常相關的條件是調用這個方法的一種可能的結果。

有兩種未受檢的異常:運行時異常和錯誤。在行為上兩種是等同:它們都不需要捕獲。如果拋出的是未受檢異?;蝈e誤,往往就屬于不可恢復的情形,繼續執行下去有害無益。如果程序未捕獲這樣的異常或錯誤,將會導致線程停止,并出現適當的錯誤消息。

用運行時異常來表明編程錯誤。大多數的運行時異常都表示違返了API規約,API的客戶同有遵守API規范。例如,數組訪問的約定指明了數組的下標值必須在零和數組長度減1之間,ArrayIndexOutOfBoundsException表明了這個規定。

按照慣例,錯誤往往被JVM保留用于表示資源不足、約束失敗,或者其他程序無法繼續執行的條件。由于這已經是個幾乎被普遍接受的慣例,因此最好不要再實現任何新的Error子類。因此,你實現的所有未受檢異常都應該是RuntimeException的子類或間接是的。

總而言這,對于可恢復的情況,使用受檢的異常;對于程序錯誤,則使用運行時異常。當然,這也不總是這么分明的。例如,考慮資源枯竭的情形,這可能是由于程序錯誤而引起的,比如分配了一塊不合理的過大的數組,也可能確實是由于資源不足而引起的。如果資源枯竭是由于臨時的短缺,或是臨時需求太大所造成的,這種情況可能就是可恢復的。API設計者需要判斷這樣的資源枯竭是否允許。如果你相信可允許恢復,就使用受檢異常,否則使用運行時異常。如果不清楚,最好使用未受檢異常。

因為受檢異常往往指明了可恢復的條件,所以,這于這樣的異常,提供一些輔助方法尤其重要,通過這些方法,調用都可以獲得一些有助于恢復的信息。例如,假設因為沒有足夠的錢,他企圖在一個收費電話上呼叫就會失敗,于是拋出檢查異常。這個異常應該提供一個訪問方法,以便用戶所缺的引用金額,從而可以將這個數組傳遞給電話用戶。

第59條:避免不必要地使用受檢異常

受檢異常與運行時異常不一樣,它們強迫程序員處理異常的條件,大大增強了可靠性,但過分使用受檢異常會使用API使用起來非常不方便。如果方法拋出一個或者多個受檢異常,調用都就必須在一個或多個catch塊中處理,或者將它們拋出并傳播出去。無論是哪種,都會給程序員添加不可忽視的負擔。

如果方法只拋出單個受檢異常,也會導致該方法不得在try塊中,在這種情況下,應該問自己,是否有別的途徑來避免API調用者使用受檢的異常。這里提供這樣的參考,我們可以把拋出的單個異常的方法分成兩個方法,其中一個方法返回一個boolean,表明是否該拋出異常。這種API重構,把下面的調用:

try{//調用時檢查異常       obj.action(args);//調用檢查異常方法}catch(TheCheckedExcption e){       // 處理異常條件       ...}123456123456

重構為:

if(obj.actionPermitted(args)){//使用狀態測試方法消除catch       obj.action(args);}else{       // 處理異常條件       ...}123456123456

這種重構并不總是合適的,但在合適的地方,它會使用API用起來更加舒服。雖然沒有前者漂亮,但更加靈活——如果程序員知道調用肯定會成功,或不介意由調用失敗而導致的線程終止,則下面為理為簡單的調用形式:

obj.action(args);11

第60條:優先使用標準異常

常見的可重用異常:

異常使用時機
IllegalArgumentException非null的參數值不正確
IllegalStateException對象狀態不適合方法調用
NullPointerException參數值是null,但這不允許
IndexOutOfBoundsException索引參數值越界
ConcurrentModificationException在禁止并發修改的情況下,檢測到對象的并發修改。
UnsupportedOperationException對象不支持的方法

一定要確保拋出的異常的條件與該異常的文檔中的描述的條件是一致的,如果希望稍微增加更多的失敗-捕獲信息,可以把現有的異常進行子類化。

第61條:拋出與抽象對象相對應的異常

如果方法拋出的異常與所執行的任務沒有明顯的聯系,這種情形將會使人不知所措,當底層的異常傳播到高層時往往會出現這種情況。這了使人困惑之外,拋出的底層異常類會污染高層的API(高層要依賴于底層異常類)。為了避免這個問題,高層在捕獲底層拋出的異常的同時,在捕獲的地方將底層的異常轉換后再重新拋出會更好:

// 異常轉換try {// 調用底層方法...} catch(LowerLevelException e) {    //捕獲底層拋出的異常后并轉換成適合自己系統的異常后再重新拋出throw new HigherLevelException(...);}1234567812345678

下面是個來自AbstractSequentialList類中的底層異常轉換的實例,該數是List的一個抽象類,它的直接子類為LinkedList,在這個例子中,按照List接口中的get方法的規范(規范中說到:如果索引超出范圍 (index < 0 || index >= size()),就會拋出IndexOutOfBoundsException異常),底層方法只要可能拋出異常,我們就需要轉換這個異常,下面是AbstractSequentialList類庫的做法:

/*** Returns the element at the specified position in this list.* @throws IndexOutOfBoundsException if the index is out of range* ({@code index < 0 || index >= size()}).*/public E get(int index) {ListIterator<E> i = listIterator(index);try {return i.next();//Iterator的next會拋出NoSuchElementException運行時異常} catch(NoSuchElementException e) {/** 但接口規范是要求拋出IndexOutOfBoundsException異常,所以需要轉換。當然這種* 轉換也是合理的,因為該方法的功能特性就是按索引來取元素,在索引越界的情況* 下拋出NoSuchElementException也是沒有太大的問題的(當然劈開規范來說的),但* 拋IndexOutOfBoundsException異常會更適合一些*/throw new IndexOutOfBoundsException("Index: " + index);}}1234567891011121314151617181912345678910111213141516171819

另一種異常轉換的形式是異常鏈,如果底層的異常對于高層調試有很大幫助時,使用異常鏈就非常合適,這樣在高層我們可以通過相應的方法來獲取底層拋出的異常:

// 異常鏈try {... // 調用底層方法} catch (LowerLevelException cause) {       // 構造異常鏈后重新拋出throw new HigherLevelException(cause);}12345671234567

盡管異常轉換與不加選擇地將捕獲到的底層異常傳播到高層中去相比有所改進,但是它不能濫用。處理來自底層異常的首選做法是根本就讓底層拋出異常,在調用底層方法前確保它會成功,從而來避免拋出異常,另外,我們有時也可以在調用底層方法前,在高層檢查一下參數的有效性,從而也可以避免異常的發生,當然這種做法(不要拋出底層異常的做法)只是對底層拋出的是運行時異常時才可行。如果確實無法避免(如低層拋出的是受檢異?;蚴沁\行時異常但根本無法阻止)低層異常時,次選方案是讓高層繞開這些異常,并將異常使用日志記錄器記錄下來供事后調試。

總之,處理底層異常最好的方法首選是阻止底層異常的發生,如果不能阻止或者處理底層異常時,一般的做法是使用異常轉換(包括異常鏈轉換),除非底層方法碰巧可以保證拋出的異常對高層也合適才可以將底層異常直接從底層傳播到高層。異常鏈對高層和低層異常都提供了最佳的功能:它允許拋出適當的高層異常的同時,又能捕獲底層的原因進行失敗分析。

第62條:每個方法拋出的異常都要有文檔描述

如果一個方法可能拋出多個異常類,則不要使用“快捷方式”聲明它會拋出這此異常類的某個超類。永遠不要聲明一個方法“throws Exception”,或者更糟的是聲明“throws Throwable”,這是極端的例子,因為它掩蓋了該方法可能拋出的其他異常。

對于方法可能拋出的未受檢異常,如果將這些異常信息很好地組織成列表文檔,就可以有效地描述出這個方法被成功執行的前提條件。每個方法的文檔應該描述它的前提條件,這是很重要的,在文檔中描述出未受檢的異常是滿中前提條件的最佳做法。

對于掊中的方法,在文檔中描述出它可能拋出的未受檢異常顯得尤其重要。這份文檔成了該接口的通用約定的一部分,它指定了該接口的多個實現必須遵循的公共行為。

未受檢異常也要在@throws標簽中進行描述。

如果某類所有方法拋出同一個異常,那么這個異常的文檔可以描述在類文檔中。

總之,要為你編寫的每個方法所能擺好出的每個異常建立文檔,對于未受檢和受檢異常,以及對于抽象的和具體的方法也都一樣。

第63條:異常信息中要包含足夠詳細的異常細節消息

異常的細節消息對異常捕獲者非常有用,對異常的診斷是非常有幫助的。

為了捕獲失敗,異常的細節消息應該包含所有“對該異常有作用”的參數和域值。例如IndexOutOfBoundsException異常的細節消息應該包含下界、上界以及沒有落在界內的下標值,因為這三個值都有可能引起這個異常。

異常的細節消息不應該與“用戶層次的錯誤消息”混為一談,后都對于最終用戶而言必須是可理解的。與用戶層次的錯誤消息不同,異常的詳細消息主要是讓程序員用來分析失敗原因的。因此,異常細節消息的內容比可理解性重要得多。

為了確保在異常的細節消息中包含足夠的能捕獲失敗的信息,一種辦法是在異常的構造器而不是字符串細節消息中引入這些信息。然后,有了這些信息,只要把它們放到消息描述中,就可以自動產生細節消息。例如,IndexOutOfBoundsException本應該這樣設計的:

/*** Construct an IndexOutOfBoundsException.** @param lowerBound the lowest legal index value.* @param upperBound the highest legal index value plus one.* @param index the actual index value.*/public IndexOutOfBoundsException(int lowerBound, int upperBound,int index) {// 構建詳細的捕獲消息super("Lower bound: " + lowerBound +", Upper bound: " + upperBound +", Index: " + index);// 存儲失敗的細節消息供程序訪問this.lowerBound = lowerBound;this.upperBound = upperBound;this.index = index;}1234567891011121314151617181912345678910111213141516171819

但遺憾的是,Java平臺類庫并沒有使用這種做法,但是,這種做法仍然值得大力推薦。

第64條:努力使失敗保持原子性

當一個對象拋出一個異常之后,我們總期望這個對象仍然保持在一種定義良好的可用狀態之中。對于被檢查的異常而言,這尤為重要,因為調用者通常期望從被檢查的異常中恢復過來。 一般而言,一個失敗的方法調用應該保持使對象保持在”它在被調用之前的狀態”。具有這種屬性的方法被稱為具有”失敗原子性(failure atomic)”??梢岳斫鉃?,失敗了還保持著原子性。對象保持”失敗原子性”的方式有幾種:

設計一個非可變對象。對于在可變對象上執行操作的方法,獲得”失敗原子性”的最常見方法是,在執行操作之前檢查參數的有效性。如下(Stack.java中的pop方法):
public Object pop() {    if (size==0)        throw new EmptyStackException();    Object result = elements[--size];    elements[size] = null;    return result;}12345671234567與上一種方法類似,可以對計算處理過程調整順序,使得任何可能會失敗的計算部分都發生在對象狀態被修改之前。編寫一段恢復代碼,由它來解釋操作過程中發生的失敗,以及使對象回滾到操作開始之前的狀態上。在對象的一份臨時拷貝上執行操作,當操作完成之后再把臨時拷貝中的結果復制給原來的對象。

雖然”保持對象的失敗原子性”是期望目標,但它并不總是可以做得到。例如,如果多個線程企圖在沒有適當的同步機制的情況下,并發的訪問一個對象,那么該對象就有可能被留在不一致的狀態中。

即使在可以實現”失敗原子性”的場合,它也不是總被期望的。對于某些操作,它會顯著的增加開銷或者復雜性。 總的規則是:作為方法規范的一部分,任何一個異常都不應該改變對象調用該方法之前的狀態,如果這條規則被違反,則API文檔中應該清楚的指明對象將會處于什么樣的狀態。

第65條:不要忽略異常

當一個API的設計者聲明一個方法會拋出某個異常的時候,他們正在試圖說明某些事情。所以,請不要忽略它!忽略異常的代碼如下:

try {    ...} catch (SomeException e) {}12341234

空的catch塊會使異常達不到應有的目的,異常的目的是強迫你處理不正常的條件。忽略一個異常,就如同忽略一個火警信號一樣 – 若把火警信號器關閉了,那么當真正的火災發生時,就沒有人看到火警信號了。所以,catch塊至少應該包含一條說明,用來解釋為什么忽略這個異常是合適的。

《Effective Java中文版 第2版》PDF版下載: http://download.csdn.net/detail/xunzaosiyecao/9745699

作者:jiankunking 出處:http://blog.csdn.net/jiankunking

from: http://blog.csdn.net/jiankunking/article/details/54879618


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久这里只有精品视频首页| 欧美日韩成人在线播放| 国产大片精品免费永久看nba| 福利微拍一区二区| 国产欧美欧洲在线观看| 日本老师69xxx| 日韩美女在线观看一区| 国产成人精品视| 欧美日韩xxxxx| 中文字幕少妇一区二区三区| 免费av在线一区| 午夜精品福利电影| 在线视频欧美日韩| 久久99国产精品自在自在app| 欧美电影在线观看高清| 成人在线中文字幕| 国产精品久久婷婷六月丁香| 91影院在线免费观看视频| 亚洲视频国产视频| 中文字幕精品www乱入免费视频| 日韩视频永久免费观看| 欧美黄色小视频| 欧美亚洲国产另类| 日韩中文字幕视频在线观看| 欧美一级大片在线免费观看| 欧美在线www| 日韩精品中文字幕视频在线| 成人亲热视频网站| 精品国产一区二区三区久久久| 97在线免费观看| 亚洲国产第一页| 国产美女被下药99| 4k岛国日韩精品**专区| 日韩女在线观看| 国产欧美日韩中文字幕在线| 久久韩剧网电视剧| 精品视频—区二区三区免费| 午夜伦理精品一区| 日韩美女免费观看| 日韩亚洲精品电影| 亚洲欧美一区二区激情| 亚洲福利视频久久| 日本久久精品视频| 国产精品九九久久久久久久| 日韩中文字幕在线视频| 久久精品99国产精品酒店日本| 久久中文精品视频| 久热精品视频在线观看| 日韩精品有码在线观看| 色先锋久久影院av| 亚洲欧美中文日韩在线v日本| 亚洲男子天堂网| 国产精品美女在线观看| 中日韩美女免费视频网址在线观看| 国产97人人超碰caoprom| 日韩欧美成人区| 5566日本婷婷色中文字幕97| 精品久久久久久久久久久久| 久久精品国产亚洲一区二区| 日本一区二区三区四区视频| 亚洲精品98久久久久久中文字幕| 色综合伊人色综合网站| 亚洲电影在线看| 国产国语videosex另类| 亚洲欧美综合精品久久成人| 欧美激情视频一区二区三区不卡| 操日韩av在线电影| 在线播放日韩av| 92版电视剧仙鹤神针在线观看| 亚洲一区二区国产| 国产精品视频精品| 欧美裸体xxxx极品少妇软件| 亚洲欧美日韩图片| 欧美成人免费播放| 久久久久久有精品国产| 欧美精品videofree1080p| 国产精品va在线播放我和闺蜜| 超碰日本道色综合久久综合| 97精品在线观看| 4k岛国日韩精品**专区| 日韩在线中文视频| 国产精品香蕉在线观看| 久久777国产线看观看精品| 亚洲一区亚洲二区亚洲三区| 久久99久久99精品中文字幕| 国产欧美一区二区三区久久人妖| 亚洲美女性生活视频| 亚洲欧美日韩在线一区| 久久精品色欧美aⅴ一区二区| 国产成人福利夜色影视| 国产美女高潮久久白浆| 国产精品九九九| 欧美孕妇性xx| 欧美亚洲成人xxx| 亚洲伊人久久大香线蕉av| 久久久视频在线| 国产精品一区电影| 日韩成人av在线播放| 色七七影院综合| 国产成人jvid在线播放| 在线观看91久久久久久| 欧美激情视频一区二区三区不卡| 国产日韩在线精品av| 亚洲一区第一页| 午夜精品在线视频| 欧美精品第一页在线播放| 国产成人精品久久久| 97视频免费在线看| 国产精品久久久久久搜索| 中文字幕成人精品久久不卡| 欧美电影在线观看完整版| 久久视频在线免费观看| 亚洲a级在线观看| 一区二区三区国产视频| 亚洲美女自拍视频| 欧美精品免费在线| 国产97在线观看| 久久久久久久一| 日韩欧美在线视频| 欧美日韩一区二区在线| 91精品视频观看| 中文字幕精品影院| 欧美成在线观看| 美女久久久久久久久久久| 一区二区三区在线播放欧美| 久久久精品亚洲| 亚洲欧美精品一区| 亚洲精品99999| 这里只有精品视频| 亚洲精品91美女久久久久久久| 欧美日韩国产精品一区二区三区四区| 国产精品久久久久久久久免费| 91免费精品国偷自产在线| 国产成人亚洲综合青青| 国产成人精品一区二区在线| 18一19gay欧美视频网站| 夜夜嗨av一区二区三区四区| 欧美日韩亚洲网| 日韩av综合中文字幕| 国产不卡视频在线| 亚洲美女精品成人在线视频| 色悠悠久久久久| 91久久夜色精品国产网站| 91av免费观看91av精品在线| 国产成人免费av| 91久久久久久国产精品| 91九色精品视频| 欧美xxxx综合视频| 国产精品大片wwwwww| 亚洲欧美制服丝袜| 亚洲成人黄色在线| 亚洲日本成人女熟在线观看| 日韩av不卡电影| 久久精品视频中文字幕| 欧美精品九九久久| 91久久精品美女高潮| 黑人狂躁日本妞一区二区三区| 日韩在线视频二区| 欧美黑人性生活视频| 久久精品99无色码中文字幕| 9.1国产丝袜在线观看| 北条麻妃一区二区在线观看| 亚洲人成电影在线观看天堂色| 成人性生交xxxxx网站|