先看一個例子:java
import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; public class UnsupportedOperation { static void test(String msg, List<String> list) { System.out.println("----------" + msg + "----------"); Collection<String> c = list; Collection<String> subList = list.subList(1, 4); Collection<String> subList2 = new ArrayList<>(subList); try { c.retainAll(subList2); } catch (Exception e) { System.out.println("retainAll: " + e); } try { c.removeAll(subList2); } catch (Exception e) { System.out.println("removeAll: " + e); } try { c.clear(); } catch (Exception e) { System.out.println("clear: " + e); } try { c.add("X"); } catch (Exception e) { System.out.println("add: " + e); } try { c.addAll(subList2); } catch (Exception e) { System.out.println("addAll: " + e); } try { c.remove("C"); } catch (Exception e) { System.out.println("remove: " + e); } try { list.set(0, "W"); } catch (Exception e) { System.err.println("List.set: " + e); } System.out.println("List.className=" + list.getClass().getSimpleName()); } public static void main(String[] args) { List<String> list = Arrays.asList("A B C D E F G".split(" ")); test("Modifiable Copy", new ArrayList<String>(list)); test("Arrays.asList", list); test("Unmodifiable List", Collections.unmodifiableList(list)); } }
執行結果:編程
----------Modifiable Copy---------- List.className=ArrayList ----------Arrays.asList---------- retainAll: java.lang.UnsupportedOperationException removeAll: java.lang.UnsupportedOperationException clear: java.lang.UnsupportedOperationException add: java.lang.UnsupportedOperationException addAll: java.lang.UnsupportedOperationException remove: java.lang.UnsupportedOperationException List.className=ArrayList ----------Unmodifiable List---------- retainAll: java.lang.UnsupportedOperationException removeAll: java.lang.UnsupportedOperationException clear: java.lang.UnsupportedOperationException add: java.lang.UnsupportedOperationException addAll: java.lang.UnsupportedOperationException remove: java.lang.UnsupportedOperationException List.set: java.lang.UnsupportedOperationException List.className=UnmodifiableRandomAccessList
那麼爲何會出現這樣的結果呢?對於Unmodifiable的List不能作修改很好理解,但從結果中能夠看到,一樣是ArrayList,爲何Array.asList()返回的List就不能作修改呢?數組
Arrays.asList()會生成一個List,它基於一個固定大小的數組,僅支持那些不會改變數組大小的操做,任何對引發底層數據結構的尺寸進行修改的方法都會產生一個UnsupportedOperationException異常,以表示對未獲支持操做的調用。數據結構
其實上面的代碼中,我故意使用的是getSimpleName(),由於這個方法不會顯示包名。若是咱們將dom
System.out.println("List.className=" + list.getClass().getSimpleName());
替換爲:設計
System.out.println("List.className=" + list.getClass().getName());
那麼結果就是這樣的了:代理
----------Modifiable Copy---------- List.className=java.util.ArrayList ----------Arrays.asList---------- retainAll: java.lang.UnsupportedOperationException removeAll: java.lang.UnsupportedOperationException clear: java.lang.UnsupportedOperationException add: java.lang.UnsupportedOperationException addAll: java.lang.UnsupportedOperationException remove: java.lang.UnsupportedOperationException List.className=java.util.Arrays$ArrayList ----------Unmodifiable List---------- retainAll: java.lang.UnsupportedOperationException removeAll: java.lang.UnsupportedOperationException clear: java.lang.UnsupportedOperationException add: java.lang.UnsupportedOperationException addAll: java.lang.UnsupportedOperationException remove: java.lang.UnsupportedOperationException List.className=java.util.Collections$UnmodifiableRandomAccessList List.set: java.lang.UnsupportedOperationException
能夠看到,Arrays.asList返回的名字雖然叫ArrayList,但此ArrayList是Arrays中的一個內部類,而非java.util.ArrayList。code
查看其源碼,能夠發現此Arrays.ArrayList內部類的聲明以下:對象
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable
而該類的實現方法中,並無實現修改E[]數組(增、刪、清除等)的方法接口
所以對這種對象調用這些方法時會調用其父類AbstractList的實現,因而就直接拋出了UnsupportedOperationException:
所以,一般的作法是,把Arrays.asList()的結果做爲構造方法的參數傳遞給任何Collection(或者使用addAll()方法或Collections.addAll()靜態方法),這樣就能夠生成容許使用全部的方法的普通容器——這在main()中的第一個對test()的調用中獲得了展現,這樣的調用會產生新的尺寸可調的底層數據結構。Collections類的「不可修改」方法將容器包裝到了一個代理中,只要你執行任何試圖修改容器的操做,這個代理就會產生UnsupportedOperationException異常。使用這些方法的目標就是產生「常量」容器對象。
test()中的最後一個try語句塊將檢查做爲List的一部分set()方法。Arrays.asList()返回固定大小的List,而Collections.unmodifiableList()產生不可修改的列表。正如輸出中看到的,修改Arrays.asList()返回的List中的元素是能夠的,由於這沒有違反「大小固定」這一特性。但很明顯,unmodifiableList()的結果在任何狀況下都是不可修改的。
--------------------------------------------------------------
像上述拋出異常的操做,在Java容器中被稱爲「未獲支持的操做」。那麼爲何會將方法定義爲可選的呢?那是由於這樣作能夠防止在設計中出現接口爆炸的狀況。爲了讓這種方式能工做:
1. UnsupportedOperationException必須是一種罕見的事件。即,對於大多數類來講,全部操做都應該能夠工做,只有在特例中才會有這類操做。在Java容器中也確實如此,由於你在99%的時間裏使用的容器類,如ArrayList、LinkedList、HashSet和HashMap,以及其餘的具體實現,都支持全部的操做。
2. 若是一個操做是未獲支持的,那麼在實現接口的時候可能就會致使UnsupportedOperationException異常,而不是將產品交付給客戶之後纔出現此異常,這種狀況是有道理的,畢竟,它表示編程上有錯誤:使用了不正確的接口實現。
值得注意的是,這類操做只有在運行時才能探測到。