Tips
《Effective Java, Third Edition》一書英文版已經出版,這本書的第二版想必不少人都讀過,號稱Java四大名著之一,不過第二版2009年出版,到如今已經將近8年的時間,但隨着Java 6,7,8,甚至9的發佈,Java語言發生了深入的變化。
在這裏第一時間翻譯成中文版。供你們學習分享之用。java
若是枚舉類型的元素主要用於集合中,通常來講使用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