国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

《Effective Java》,關(guān)于異常

CoorChice / 1921人閱讀

摘要:只針對異常的情況才使用異常下面展示兩種遍歷數(shù)組元素的實現(xiàn)方式。第一種方式在訪問數(shù)組邊界之外的第一個數(shù)組元素時,用拋出捕獲忽略異常的手段來達到終止無限循環(huán)的目的。這種做法被稱為異常轉(zhuǎn)譯。

只針對異常的情況才使用異常

下面展示兩種遍歷數(shù)組元素的實現(xiàn)方式。

try {
    int i = 0;
    while(true)
        range[i++].climb();
} catch(ArrayIndexOutOfBoundsException e) {

}
for (Mountain m : range)
    m.climb();

第一種方式在訪問數(shù)組邊界之外的第一個數(shù)組元素時,用拋出、捕獲、忽略異常的手段來達到終止無限循環(huán)的目的。

第二種方式是數(shù)組循環(huán)的標準模式。

基于異常的循環(huán)模式不僅模糊了代碼的意圖,降低了性能,而且還不能保證正常工作。

異常應該只用于異常的情況下,不應該用于正常的控制流。
應該優(yōu)先使用標準的、容易理解的模式,而不是那些聲稱可以提供更好性能的、弄巧成拙的方法。

設計良好的API不應該強迫客戶端為了正常的控制流而使用異常。
如果類具有“狀態(tài)相關(guān)”的方法,即只有特定的不可預知的條件下才可以被調(diào)用的方法,這個類往往也應該有個多帶帶的“狀態(tài)測試”方法,即指示是否可以調(diào)用這個狀態(tài)相關(guān)的方法。
例如,Iterator接口有一個“狀態(tài)相關(guān)”的next方法,和相應的狀態(tài)測試方法hasNext方法。

for(Iterator i = collection.iterator(); i.hasNext(); ) {
    Foo foo = i.next();
}

如果Iterator缺少hasNext方法,客戶端將被迫改用下面的做法:

try {
    Iterator i = collection.iterator();
    while(true) {
        Foo foo = i.next();
    }
} catch (NoSuchElementException e) {

}
對可恢復的情況使用受檢異常,對編程錯誤使用運行時異常

Java提供了三種可拋出結(jié)構(gòu):受檢的異常(checked exception)、運行時異常(run-time exception)和錯誤(error)。

如果期望調(diào)用者能夠適當?shù)鼗謴停褂檬軝z的異常。

兩種未受檢的可拋出結(jié)構(gòu):運行時異常和錯誤。
在行為上兩者是等同的:都是不需要也不應該被捕獲的可拋出結(jié)構(gòu)。

用運行時異常表明編程錯誤。大多數(shù)的運行時異常都表示前提違例(precondition violation)。前提違例是指API的客戶沒有遵守API規(guī)范建立的約定。例如,數(shù)組訪問的約定指明了數(shù)組的下標值必須在零和數(shù)組長度減1之間。ArrayIndexOutOfBoundsException表明這個前提被違反了。

最好,所有未受檢的拋出結(jié)構(gòu)都應該是RuntimeException的子類。

避免不必要地使用受檢的異常

過分使用受檢的異常會使API使用起來非常不方便。
如果方法拋出一個或者多個受檢的異常,調(diào)用該方法的代碼就必須在一個或者多個catch塊中處理這些異常,或者聲明它拋出這些異常,并讓它們傳播出去。

如果正確地使用API并不能阻止這種異常條件的產(chǎn)生,并且一旦產(chǎn)生異常,使用API的程序員可以立即采取有用的動作,這種負擔就被認為是正當?shù)摹3沁@兩個條件都成立,否則更適合于使用受檢的異常。

“把受檢的異常變成未受檢的異常”的一種方法是,把這個拋出異常的方法分成兩個方法,其中一個方法返回一個boolean,表明是否應該拋出異常。

try {
    obj.action(args);
} catch(TheCheckedException e) {
    // Handle exceptional condition
    ...
}

重構(gòu)為:

if (obj.actionPermitted(args)) {
    obj.action(args);
} else {
    // Handle exceptional condition
    ...
}

如果對象在缺少外部同步的情況下被并發(fā)訪問,或者可被外界改變狀態(tài),這種重構(gòu)就是不恰當?shù)摹R驗樵赼ctionPermitted和action這兩個調(diào)用的時間間隔之中,對象的狀態(tài)有可能會發(fā)生變化。如果多帶帶的actionPermitted方法必須重復action方法的工作,出于性能的考慮,這種API重構(gòu)就不值得去做。

優(yōu)先使用標準的異常

Java平臺類庫提供了一組基本的未受檢的異常,它們滿足了絕大多數(shù)API的異常拋出需要。

重用現(xiàn)有的異常有多方面的好處。其中最主要的好處是,使API更加易于學習和使用,因為它與程序員已經(jīng)熟悉的習慣用法是一致的。第二個好處是,可讀性會更好,因為不會出現(xiàn)很多程序員不熟悉的異常。

常用的異常以及其使用場合:
IllegalArgumentException(非null的參數(shù)值不正確)
IllegalStateException(對于方法調(diào)用而言,對象狀態(tài)不合適)
NullPointerException(在禁止使用null的情況下參數(shù)值為null)
IndexOutOfBoundsException(下標參數(shù)值越界)
ConcurrentModificationException(在禁止并發(fā)修改的情況下,檢測到對象的并發(fā)修改)
UnsupportedOperationException(對象不支持用戶請求的方法)

選擇重用哪個異常并不總是那么精準,因為上表中的“使用場合”并不是相互排斥的。

拋出與抽象相對應的異常

如果方法拋出的異常與它所執(zhí)行的的任務沒有明顯的關(guān)系,這種情形將會使人不知所措。

為了避免這個問題,更高層的實現(xiàn)應該捕獲低層的異常,同時拋出可以按照高層抽象進行解釋的異常。這種做法被稱為異常轉(zhuǎn)譯(exception translation)。

取自AbstractSequentialList類的異常轉(zhuǎn)譯例子:

/**
 * Returns the element at the specified position in this list.
 *
 * 

This implementation first gets a list iterator pointing to the * indexed element (with listIterator(index)). Then, it gets * the element using ListIterator.next and returns it. * * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { try { return listIterator(index).next(); } catch (NoSuchElementException exc) { throw new IndexOutOfBoundsException("Index: "+index); } }

一種特殊的異常轉(zhuǎn)譯形式稱為異常鏈(exception chaining)。如果低層的異常對于調(diào)試導致高層異常的問題非常有幫助,使用異常鏈就很合適。

// Exception Chaining
try {
    // use lower-level abstraction to do our bidding
} catch(LowerLevelException cause) {
    throw new HigherLevelException(cause);
}
// Exception with chaining-aware constructor
class HigherLevelException extends Exception {
    HigherLevelException(Throwable cause) {
        super(cause);
    }
}

異常鏈不僅讓你可以通過程序(用getCause)訪問原因,還可以將原因的堆棧軌跡集成到更高層的異常中。

處理來自低層異常的最好做法是,在調(diào)用低層方法之前確保它們會成功執(zhí)行,從而避免它們拋出異常。有時候,在給低層傳遞參數(shù)之前,檢查更高層方法的參數(shù)的有效性,也能避免低層方法拋出異常。

如果無法避免低層異常,可以將異常記錄下來。這樣有助于調(diào)查問題,同時又將客戶端代碼和最終用戶與問題隔離開。

總之,如果不能阻止或者處理來自低層的異常,一般做法是使用異常轉(zhuǎn)譯,除非低層方法碰巧可以保證它拋出的所有異常對高層也合適,才可以將異常從低層傳播到高層。異常鏈對高層和低層異常都提供了最佳的功能:允許拋出適當?shù)母邔赢惓#瑫r又能捕獲低層的原因進行分析。

每個方法拋出的異常都要有文檔

始終要多帶帶地聲明受檢的異常,并且利用Javadoc的@throws標記,準確地記錄下拋出每個異常的條件。

使用Javadoc的@throws標簽記錄下一個方法可能拋出的每個未受檢異常,但是不要使用throws關(guān)鍵字將未受檢的異常包含在方法的聲明中。

如果一個類中的許多方法出于同樣的原因而拋出同一個異常,在該類的文檔注釋中對這個異常建立文檔,這是可以接受的,而不是為每個方法多帶帶建立文檔。

在細節(jié)消息中包含能捕獲失敗的信息

當程序由于未被捕獲的異常而失敗的時候,系統(tǒng)會自動地打印該異常的堆棧軌跡。在堆棧軌跡中包含該異常的字符串表示法,即它的toString方法的調(diào)用結(jié)果。異常類型的toString方法應該盡可能多地返回有關(guān)失敗原因的信息。

為了捕獲失敗,異常的細節(jié)信息應該包含所有“對該異常有貢獻”的參數(shù)和域的值。

為了確保在異常的細節(jié)信息中包含足夠的能捕獲失敗的信息,一種辦法是在異常的構(gòu)造器中引入這些信息。例如:

/**
 * 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;
}
努力使失敗保持原子性

一般而言,失敗的方法調(diào)用應該使對象保持在被調(diào)用之前的狀態(tài)。具有這種屬性的方法被稱為具有失敗原子性(failure atomic)。

有四種途徑可以實現(xiàn)這種效果。

第一種是設計一個不可變的對象。

第二種是在執(zhí)行操作之前檢查參數(shù)的有效性。這可以使得在對象的狀態(tài)被修改之前,先拋出適當?shù)漠惓!@纾琒tack.pop方法。

public Object pop() {
    if (size == 0)
        throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null; // Eliminate obsolete reference
    return result;
}

還有類似的辦法是,調(diào)整計算處理過程的順序,使得任何可能會失敗的計算部分都在對象狀態(tài)被修改之前發(fā)生。

第三種是編寫一段恢復代碼,來攔截操作過程中發(fā)生的失敗,以及使對象回滾到操作開始之前的狀態(tài)。這種辦法主要用于永久性的數(shù)據(jù)結(jié)構(gòu)。

第四種是在對象的一份臨時拷貝上執(zhí)行操作,當操作完成之后再用臨時拷貝中的結(jié)果代替對象的內(nèi)容。

一般,作為方法規(guī)范的一部分,產(chǎn)生的任何異常都應該讓對象保持在該方法調(diào)用之前的狀態(tài)。

不要忽略異常

當API的設計者聲明一個方法將拋出某個異常的時候,等于正在試圖說明某些事情。所以,請不要忽略它。

有一種情形可以忽略異常,即關(guān)閉FileInputStream的時候。因為還沒有改變文件的狀態(tài),因此不必執(zhí)行任何恢復動作,并且已經(jīng)從文件中讀取到所需要的信息,因此不必終止正在進行的操作。即使在這種情況下,把異常記錄下來還是明智的做法。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70002.html

相關(guān)文章

  • Java 高效編程(Effective Java)中文第三版

    摘要:來源前條來源一書英文版已經(jīng)出版,這本書的第二版想必很多人都讀過,號稱四大名著之一,不過第二版年出版,到現(xiàn)在已經(jīng)將近年的時間,但隨著,,,甚至的發(fā)布,語言發(fā)生了深刻的變化。譯者在這里第一時間翻譯成中文版。供大家學習分享之用。 來源:sjsdfg/effective-java-3rd-chinese前 51 條來源:Effective Java, Third Edition 《Effec...

    ysl_unh 評論0 收藏0
  • effective java 觀后感

    摘要:這本書是我第一次買的,從買來至今整本書還沒有看完,只看了一半,原因是個人比較懶,而且玩的心比較大,經(jīng)過這么多年的沉淀,終于可以偷點時間寫下對于這本書的觀后感了整本書給我的感覺不像是一個技術(shù)書,更多的是講解一些實用技巧,而對于我這個職場菜鳥來 effective Java 這本書是我第一次買的, 從買來至今整本書還沒有看完, 只看了一半, 原因是個人比較懶,而且玩的心比較大,經(jīng)過這么多年...

    calx 評論0 收藏0
  • Effective Java 第三版 全文翻譯

    摘要:本章中的大部分內(nèi)容適用于構(gòu)造函數(shù)和方法。第項其他方法優(yōu)先于序列化第項謹慎地實現(xiàn)接口第項考慮使用自定義的序列化形式第項保護性地編寫方法第項對于實例控制,枚舉類型優(yōu)先于第項考慮用序列化代理代替序列化實例附錄與第版中項目的對應關(guān)系參考文獻 effective-java-third-edition 介紹 Effective Java 第三版全文翻譯,純屬個人業(yè)余翻譯,不合理的地方,望指正,感激...

    galois 評論0 收藏0
  • Effective Java 3rd.Edition 翻譯

    摘要:推薦序前言致謝第一章引言第二章創(chuàng)建和銷毀對象第項用靜態(tài)工廠方法代替構(gòu)造器第項遇到多個構(gòu)造器參數(shù)時要考慮使用構(gòu)建器第項用私有構(gòu)造器或者枚舉類型強化屬性第項通過私有構(gòu)造器強化不可實例化的能力第項優(yōu)先考慮依賴注入來引用資源第項避免創(chuàng)建不必要的對象 推薦序 前言 致謝 第一章 引言 第二章 創(chuàng)建和銷毀對象 第1項:用靜態(tài)工廠方法代替構(gòu)造器 第2項:遇到多個構(gòu)造器參數(shù)時要考慮使用構(gòu)建器 第...

    KoreyLee 評論0 收藏0
  • Effective Java 筆記

    摘要:如果采用抽象類,則屬性組合可能導致子類的組合爆炸。內(nèi)部類的設計靜態(tài)成員類用修飾的內(nèi)部類,可以不依賴于外部實例進行創(chuàng)建。如下所示其構(gòu)造函數(shù)默認是,并且無法修改。 對所有對象都通用的方法 equals和hashCode方法的關(guān)系 重寫equals方法必須也要重寫hashCode方法。 equals用的屬性沒變,則多次調(diào)用hashCode返回值也必須保持不變。 equals比較相等的對象,...

    enali 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<