利用static(靜態)數組Arrays.toList(),也許能將一個數組轉換成List,如下所示:
//: Unsupported.java // Sometimes methods defined in the Collection // interfaces don't work! package c08.newcollections; import java.util.*; public class Unsupported { private static String[] s = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", }; static List a = Arrays.toList(s); static List a2 = Arrays.toList( new String[] { s[3], s[4], s[5] }); public static void main(String[] args) { Collection1.print(a); // Iteration System.out.println( "a.contains(" + s[0] + ") = " + a.contains(s[0])); System.out.println( "a.containsAll(a2) = " + a.containsAll(a2)); System.out.println("a.isEmpty() = " + a.isEmpty()); System.out.println( "a.indexOf(" + s[5] + ") = " + a.indexOf(s[5])); // Traverse backwards: ListIterator lit = a.listIterator(a.size()); while(lit.hasPrevious()) System.out.print(lit.previous()); System.out.println(); // Set the elements to different values: for(int i = 0; i < a.size(); i++) a.set(i, "47"); Collection1.print(a); // Compiles, but won't run: lit.add("X"); // Unsupported operation a.clear(); // Unsupported a.add("eleven"); // Unsupported a.addAll(a2); // Unsupported a.retainAll(a2); // Unsupported a.remove(s[0]); // Unsupported a.removeAll(a2); // Unsupported } } ///:~
從中可以看出,實際只實現了Collection和List接口的一部分。剩余的方法導致了不受歡迎的一種情況,名為UnsupportedOperationException。在下一章裡,我們會講述違例的詳細情況,但在這裡有必要進行一下簡單說明。這裡的關鍵在於“集合接口”,以及新集合庫內的另一些接口,它們都包含了“可選的”方法。在實現那些接口的集合類中,或者提供、或者沒有提供對那些方法的支持。若調用一個未獲支持的方法,就會導致一個UnsupportedOperationException(操作未支持違例),這表明出現了一個編程錯誤。
大家或許會覺得奇怪,不是說“接口”和基礎類最大的“賣點”就是它們許諾這些方法能產生一些有意義的行為嗎?上述違例破壞了那個許諾——它調用的一部分方法不僅不能產生有意義的行為,而且還會中止程序的運行。在這些情況下,類型的所謂安全保證似乎顯得一錢不值!但是,情況並沒有想象的那麼壞。通過Collection,List,Set或者Map,編譯器仍然限制我們只能調用那個接口中的方法,所以它和Smalltalk還是存在一些區別的(在Smalltalk中,可為任何對象調用任何方法,而且只有在運行程序時才知道這些調用是否可行)。除此以外,以Collection作為自變量的大多數方法只能從那個集合中讀取數據——Collection的所有“read”方法都不是可選的。
這樣一來,系統就可避免在設計期間出現接口的沖突。而在集合庫的其他設計方案中,最終經常都會得到數量過多的接口,用它們描述基本方案的每一種變化形式,所以學習和掌握顯得非常困難。有些時候,甚至難於捕捉接口中的所有特殊情況,因為人們可能設計出任何新接口。但Java的“不支持的操作”方法卻達到了新集合庫的一個重要設計目標:易於學習和使用。但是,為了使這一方法真正有效,卻需滿足下述條件:
(1) UnsupportedOperationException必須屬於一種“非常”事件。也就是說,對於大多數類來說,所有操作都應是可行的。只有在一些特殊情況下,一、兩個操作才可能未獲支持。新集合庫滿足了這一條件,因為絕大多數時候用到的類——ArrayList,LinkedList,HashList和HashMap,以及其他集合方案——都提供了對所有操作的支持。但是,如果想新建一個集合,同時不想為集合接口中的所有方法都提供有意義的定義,同時令其仍與現有庫配合,這種設計方法也確實提供了一個“後門”可以利用。
(2) 若一個操作未獲支持,那麼UnsupportedOperationException(未支持的操作違例)極有可能在實現期間出現,則不是在產品已交付給客戶以後才會出現。它畢竟指出的是一個編程錯誤——不正確地使用了一個類。這一點不能十分確定,通過也可以看出這種方案的“試驗”特征——只有經過多次試驗,才能找出最理想的工作方式。
在上面的例子中,Arrays.toList()產生了一個List(列表),該列表是由一個固定長度的數組後推出來的。因此唯一能夠支持的就是那些不改變數組長度的操作。在另一方面,若請求一個新接口表達不同種類的行為(可能叫作“FixedSizeList”——固定長度列表),就有遭遇更大的復雜程度的危險。這樣一來,以後試圖使用庫的時候,很快就會發現自己不知從何處下手。
對那些采用Collection,List,Set或者Map作為參數的方法,它們的文檔應當指出哪些可選的方法是必須實現的。舉個例子來說,排序要求實現set()和Iterator.set()方法,但不包括add()和remove()。