集合框架特性

瞭解新的集合型別及現有類和介面的附加特性

JDK 5。0 中最吸引人的地方在於集合框架的一些最突出的特性上,例如:支援泛型的語言級別上的新變化,以及可以在 java。util。concurrent 包中找到的併發集合工具包。實際上,以前在 developerWorks 上的“馴服 Tiger: 併發集合”和“介紹 JDK 5。0 中的泛型”這兩篇教程中介紹了上述特性。但是其他增強還沒有得到足夠的重視。在本文中,我將研究其他三個變化:更新過的 Arrays 和 Collections 類、新的 Queue 介面以及它的 PriorityQueue 實現。

陣列(Array)

Arrays 類提供了一系列處理陣列的靜態工具方法,這些索引的資料結構的大小是固定的。在 5。0 版本之前,Arrays 類擁有針對原始資料庫型別和通用 Object 型別的每種不同陣列型別的 binarySearch()、equals()、fill() 和 sort() 方法。用於將 Object 陣列轉換成 List 的附加 asList() 方法仍然有用。Tiger 為所有陣列添加了 hashCode() 和 toString() 方法,還添加了特定於 Object 陣列的 deepEquals()、deepHashCode() 和 deepToString() 方法。總計有 21 個新方法可用:

public static boolean deepEquals(Object[] a1, Object[] a2)

public static int deepHashCode(Object[] a)

public static String deepToString(Object[] a)

public static int hashCode(boolean[] a)

public static int hashCode(byte[] a)

public static int hashCode(char[] a)

public static int hashCode(double[] a)

public static int hashCode(float[] a)

public static int hashCode(int[] a)

public static int hashCode(long[] a)

public static int hashCode(Object[] a)

public static int hashCode(short[] a)

public static String toString(boolean[] a)

public static String toString(byte[] a)

public static String toString(char[] a)

public static String toString(double[] a)

public static String toString(float[] a)

public static String toString(int[] a)

public static String toString(long[] a)

public static String toString(Object[] a)

public static String toString(short[] a)

自從集合框架初次出現在 J2SE 1。2 中以來,人們第一次對實用工具類進行了更改。我無法確定為什麼 Sun 要等這麼久才進行更改,但是對於可用的幫助器方法系列來說,這些更改是受歡迎的新增。

新新增的第一個方法是 hashCode()。對於任意陣列型別,都可以呼叫 Arrays。hashCode(arrayVar) 方法來獲得格式良好的雜湊碼。這個雜湊碼可以用作 HashMap 或者其他相關目的的鍵。如果您不知道如何生成良好的雜湊碼,那麼最好使用 Arrays 類,它能產生更少衝突。Arrays 類生成等價於擁有相同元素的 List 的程式碼。

在建立自己的類時,既需要提供 equals() 方法,又需要提供 hashCode() 方法。在 Arrays 的新方法 hashCode() 的幫助下,可以為任何本地陣列型別生成雜湊碼,而不用在每次需要它的時候折騰您自己。

所有陣列型別都可用的另一個方法是 toString()。對於任何陣列型別,都可以呼叫Arrays。toString(arrayVar) 獲得逗號分隔的元素列表,列表用方括號包圍,如清單 1 的程式所示:

清單 1。 用 Arrays。toString 生成字串

import java。util。Arrays;public class ArgsToString { public static void main(String args[]) { System。out。println(Arrays。toString(args)); }}

清單 2 顯示了結果:

清單 2。 清單 1 的結果

>java ArgsToString One Two Three [One, Two, Three]

新的 deepEquals()、deepHashCode() 和 deepToString() 方法的工作方式類似於它們那些非深度(non-deep)的同類,但它們不僅會停下手來處理頂級陣列的每個元素,還會更深入地研究生成結果的多維陣列。

雖然不是一個新方法,但 asList() 方法在 5。0 的工作方式有所不同。以前,這個方法接受 Object[] 陣列作為它的引數。現在,因為 Tiger 的可變引數列表特性,任何用逗號分隔的列表都可以接受,如清單 3 所示:

清單 3。 Arrays。asList 的區別

import java。util。Arrays;public class AsList { public static void main(String args[]) { // Before List before = Arrays。asList(args); // After List after = Arrays。asList(“One”, “Two”, “Three”); }}

如果傳遞給命令列的元素不同,清單 3 中的兩個示例沒必要產生同樣的結果 ,但是它確實展示了 Tiger 在語言級別上的變化如何擴充套件了 Arrays 原有的 asList() 方法。

集合

Arrays 用於處理不同集合的輔助類是 Collections 類。同樣,這個類也不是一個新類,但是該類的特性已經針對 5。0 作了擴充套件。現在有 13 個新方法:

checkedCollection()

checkedSet()

checkedSortedSet()

checkedList()

checkedMap()

checkedSortedMap()

emptySet()

emptyList()

emptyMap()

reverseOrder()

frequency()

disjoint()

addAll()

其中 6 個 checked*() 方法工作起來與 6 個 synchronized*() 和 unmodifiable*() 方法類似。使用 synchronized*() 方法時,要向該方法提供一個集合,然後該方法將返回同一個集合的同步的、執行緒安全的版本。使用 unmodifiable*() 方法時,得到的是指定集合的只讀檢視。除了集合引數之外,checked*() 操作可能還要求第二個或者第三個引數(如清單 4 所示),並返回該集合的動態的型別安全檢視:

清單 4。 檢測後的集合

public static Collection checkedCollection( Collection c, Class type)public static Set checkedSet( Set s, Class type)public static SortedSet checkedSortedSet( SortedSet s, Class type)public static List checkedList( List list, Class type)public static Map checkedMap( Map m, Class keyType, Class valueType)public static SortedMap checkedSortedMap( SortedMap m, Class keyType, Class valueType)

使用 Java 5。0 平臺,您可能以為:由於將集合宣告為通用集合 (Collection c = new HashSet();),所以不需要進行執行時檢測了。但是如果向工具方法傳遞 String 版本的 HashSet,而工具方法只能處理非通用的 Set,那麼該方法可能就會錯誤地向集合新增一個非 String 元素。透過臨時修改程式,用 Collection c = Collections。checkedCollection(new HashSet(), String。class); 新增執行時檢查,您可以迅速發現問題的根源。

三個 empty*() 方法 —— emptySet()、emptyList() 和 emptyMap() —— 生成空的不可改變的集合。雖然也可以用 new ArraySet() 這樣的方法建立空集合,但是還要透過某個 unmodifiable*() 方法才能確保新集合是不可改變的。empty 方法用更理想的方式提供了空的只讀集合。

佇列(Queue)介面

5。0 集合框架較大的一個改變就是添加了新的基介面 Queue。雖然這個介面是在“併發集合”技巧 (請參閱 參考資料)中描述的,但它的應用並不限於併發。在計算機科學中,佇列資料結構是基本的先進先出(FIFO) 結構。專案新增到尾部,並且要從頂部刪除。不僅能新增和刪除元素,還能檢視佇列中有哪些元素。清單 5 顯示了 Queue 介面的 5 個方法:

清單 5。 Queue 介面

public boolean offer(Object element)public Object remove()public Object poll()public Object element()public Object peek()

請記住,Queue 是從 Collection 介面擴充套件的,所以實現 Queue 介面也就實現了 Collection。在使用 Queue 的實現時,應當將自己限制在介面的方法上。例如,向 Queue 新增元素可以用 Collection 的 add() 方法來實現,它在失敗時會丟擲未檢測異常。相反,如果大小有限的佇列滿了,那麼 offer() 方法會返回 false,而不需要處理佇列滿的異常。

java。util。concurrent 包中具有 Queue 介面的多個實現,但並不包含所有實現。LinkedList 類針對 JDK 5。0 的 Queue 介面作了修正,而 PriorityQueue 是隨 JDK 5。0 新增進來的。餘下的實現 —— ArrayBlockingQueue、ConcurrentLinkedQueue、DelayQueue、LinkedBlockingQueue、PriorityBlockingQueue 和 SynchronousQueue —— 都是 java。util。concurrent 包的組成部分。

因為 LinkedList 不是新事物,所以我們來看一下新的 PriorityQueue 類。如清單 6 所示,可以用 6 種方法建立它。在不能使用 Comparator 時,可以使用元素的自然順序來確定優先順序。如果元素沒有實現 Comparable 介面,那麼就會產生執行時錯誤:

清單 6。 PriorityQueue 建構函式

PriorityQueue() PriorityQueue(Collection<? extends E> c) PriorityQueue(int initialCapacity) PriorityQueue(int initialCapacity, Comparator<? super E> comparator) PriorityQueue(PriorityQueue<? extends E> c) PriorityQueue(SortedSet<? extends E> c)

為了演示 PriorityQueue 的用法,清單 7 中的程式添加了所有命令列元素,並按字母順序處理它們。由於佇列結構是 LinkedList,所以順序應當是典型的 FIFO 順序,但是 PriorityQueue 將根據優先順序對元素進行排序:

清單 7。 PriorityQueue 的用法

import java。util。*;import java。util。concurrent。*;public class Priority { public static void main(String args[]) { Queue queue = new PriorityQueue(Arrays。asList(args)); String element; while ((element = queue。poll()) != null) { System。out。println(element); } }}

清單 8 顯示了用命令列 one two three four 執行程式之後的輸出 :

清單 8。 清單 7 的結果

>java Priority one two three four four one three two

關於新的 Queue 介面,有件事需要提一下,這件事與 Collections 類有關:方法 checkedQueue()、emptyQueue()、synchronizedQueue() 和 unmodifiableQueue() 全都是 Collections 類中所缺少的。根據 bug 報告,除了 checkedQueue() 之外,所有類都是故意缺失的。對於 synchronizedQueue(),併發集合是比純粹的包裝器更好的選擇。其他方法則被認為不是必需的。也許 Tiger/6。0 版本中會新增 checkedQueue()(和 checkedBlockingQueue()) 。

集合框架特性