Effective Java 第三版——36. 使用EnumSet替代位屬性

Tips
《Effective Java, Third Edition》一書英文版已經出版,這本書的第二版想必不少人都讀過,號稱Java四大名著之一,不過第二版2009年出版,到如今已經將近8年的時間,但隨着Java 6,7,8,甚至9的發佈,Java語言發生了深入的變化。
在這裏第一時間翻譯成中文版。供你們學習分享之用。java

Effective Java, Third Edition

36. 使用EnumSet替代位屬性

若是枚舉類型的元素主要用於集合中,通常來講使用int枚舉模式(條目 34),下面將2的不一樣倍數賦值給每一個常量:程序員

// Bit field enumeration constants - OBSOLETE!
public class Text {
    public static final int STYLE_BOLD          = 1 << 0;  // 1
    public static final int STYLE_ITALIC        = 1 << 1;  // 2
    public static final int STYLE_UNDERLINE     = 1 << 2;  // 4
    public static final int STYLE_STRIKETHROUGH = 1 << 3;  // 8

    // Parameter is bitwise OR of zero or more STYLE_ constants
    public void applyStyles(int styles) { ... }
}

這種表示方式容許你使用按位或(or)運算將幾個常量合併到一個稱爲位屬性(bit field)的集合中:安全

text.applyStyles(STYLE_BOLD | STYLE_ITALIC);

位屬性表示還容許你使用按位算術有效地執行集合運算,如並集和交集。 可是位屬性具備int枚舉常量等的全部缺點。 當打印爲數字時,解釋位屬性比簡單的int枚舉常量更難理解。 沒有簡單的方法遍歷全部由位屬性表示的元素。 最後,必須預測在編寫API時須要的最大位數,並相應地爲位屬性(一般爲int或long)選擇一種類型。 一旦你選擇了一個類型,你就不能超過它的寬度(32或64位)而不改變API。app

一些程序員使用枚舉優於int常量,當他們須要傳遞常量集合時仍然使用位屬性。 沒有理由這樣作,由於存在更好的選擇。 java.util包提供了EnumSet類來有效地表示從單個枚舉類型中提取的值集合。 這個類實現了Set接口,提供了全部其餘Set實現的豐富性,類型安全性和互操做性。 可是在內部,每一個EnumSet都表示爲一個位矢量(bit vector)。 若是底層的枚舉類型有64個或更少的元素,而且大多數狀況下,整個EnumSet用單個long表示,因此它的性能與位屬性的性能至關。 批量操做(如removeAll和retainAll)是使用按位算術實現的,就像你爲位屬性手動操做同樣。 可是徹底避免了手動位混亂的醜陋和錯誤傾向:EnumSet爲你作了很大的努力。性能

下面是前一個使用枚舉和枚舉集合替代位屬性的示例。 它更短,更清晰,更安全:學習

// EnumSet - a modern replacement for bit fields
public class Text {
    public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }

    // Any Set could be passed in, but EnumSet is clearly best
    public void applyStyles(Set<Style> styles) { ... }
}

這裏是將EnumSet實例傳遞給applyStyles方法的客戶端代碼。 EnumSet類提供了一組豐富的靜態工廠,能夠輕鬆建立集合,其中一個代碼以下所示:翻譯

text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));

請注意,applyStyles方法採用Set<Style>而不是EnumSet<Style>參數。 儘管全部客戶端均可能會將EnumSet傳遞給該方法,但接受接口類型而不是實現類型一般是很好的作法(條目 64)。 這容許一個不尋常的客戶端經過其餘Set實現的可能性。code

總之,僅僅由於枚舉類型將被用於集合中,因此沒有理由用位屬性來表示它EnumSet類將位屬性的簡潔性和性能與條目 34中所述的枚舉類型的全部優勢相結合。EnumSet的一個真正缺點是,它不像Java 9那樣建立一個不可變的EnumSet,可是在即將發佈的版本中可能會獲得補救。 同時,你能夠用Collections.unmodifiableSet封裝一個EnumSet,可是簡潔性和性能會受到影響。blog

相關文章
相關標籤/搜索