先看一个例子: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异常,而不是将产品交付给客户之后才出现此异常,这种状况是有道理的,毕竟,它表示编程上有错误:使用了不正确的接口实现。
值得注意的是,这类操做只有在运行时才能探测到。