top
Loading...
馴服Tiger(J2SE5.0)之集合框架
JDK 5.0 中最吸引人的地方在于集合框架的一些最突出的特性上,例如:支持泛型的語言級別上的新變化,以及可以在 java.util.concurrent 包中找到的并發集合工具包。在本文中,我將研究其他三個變化:更新過的 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 <E> Collection<E> checkedCollection(     Collection<E> c, Class<E> type)   public static <E> Set<E> checkedSet(     Set<E> s, Class<E> type)   public static <E> SortedSet<E> checkedSortedSet(     SortedSet<E> s, Class<E> type)   public static <E> List<E> checkedList(     List<E> list, Class<E> type)   public static <K,V> Map<K,V> checkedMap(     Map<K,V> m, Class<K> keyType, Class<V> valueType)   public static <K,V> SortedMap<K,V> checkedSortedMap(     SortedMap<K,V> m, Class<K> keyType, Class<V> valueType) 

使用 Java 5.0 平臺,您可能以為:由于將集合聲明為通用集合 (Collection<String> c = new HashSet<String>();),所以不需要進行運行時檢測了。但是如果向工具方法傳遞 String 版本的 HashSet,而工具方法只能處理非通用的 Set,那么該方法可能就會錯誤地向集合添加一個非 String 元素。通過臨時修改程序,用 Collection<String> c = Collections.checkedCollection(new HashSet<String>(), 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<String> queue =       new PriorityQueue<String>(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(),并發集合是比純粹的包裝器更好的選擇。其他方法則被認為不是必需的。也許新版本中會添加 checkedQueue()(和 checkedBlockingQueue()) 。
作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗