我们在使用collection框架code时,会时常遇到UnsupportedOperationException异常,有些人很不了解为什么抛出这个异常,会很郁闷。下面我作一下解释,可能也不是很正确。
其实我们主要的疑惑可能是:java既然提供了这个方法,为什么我们调用要抛出异常,说不支持这个操作。我们先看一段代码:
List list1 = new ArrayList();
list1.add("test");
String[] array = new String[2];
List list2 = Arrays.asList(array);
List list3 = new ArrayList(list2);
list3.add("test");
array[0] = "test2";
System.out.println(list2.get(0));
list2.add("test");//抛出异常
在执行到l2.add("test")时抛出如下异常:
test2
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:151)
at java.util.AbstractList.add(AbstractList.java:89)
at TesException.main(TesException.java:20)
为什么会这样呢?
解释如下:
上面代码中list1是用正常方式下创建的List,可以增删内容
而list2是一个固定大小的List,不可以对其进行进行修改操作,对array的任何操作,若想修改list3的内容,只能通过修改其对应的array,从上面这一点也是可以看出的(关于这些解释可以参看api文档)。那么为什么会这样呢,其实List结构按是否可修改也是可以在分为两个类型的,但是collection框架已经有太多的接口类型了,若在对每种接口类型都分出一个unmodifiable类型的接口,那么最后collection框架会更大,对于学习与使用都会需要记住更多的接口。所以我想这样做的关键一点是:统一接口,减少开发人员的负担。但是若文档中没有对这一点说清楚,有些喜欢刨根问题的程序员会很郁闷。
我猜测Arrays.asList返回的List内容是Array的内容引用。若可以在List中修改,那么怎么同步呢?因为它们有一个本质的区别Array不能自动增大,若允许在List随便增大,则与其相应的Array的内容怎么保证不可修改呢?他们之间有一个阻抗。最后权衡一下,只能让Arrays.asList返回的List不可修改,或者让返回的List与Array之间没有关系,若这样的话,对于那些很大数组来说性能上就会很有影响。
详情看如下代码:
String s[]=new String[2];
List list3 = Arrays.asList(s);
List list4 = new ArrayList<>(list3);
list4.add("test");
s[0] = "test2";
System.out.println(list3.get(0));//test2
System.out.println(list3.get(1));//null
System.out.println(list3.size());//2
System.out.println(list4.size());//3
//list3.add("test");//抛出异常
list4.add("test");//没有抛出异常
System.out.println(list4.get(2));//test
System.out.println(list4.get(3));//test
System.out.println(list4.get(0));//null
System.out.println(list4.get(1));//null
List list5 = new ArrayList<>(list3);
System.out.println(list5.size());//2
System.out.println(list5.get(0));//test2
System.out.println(list5.get(1));//null
还可以简写成: List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
public static <T> List<T> asList(T... a)
-
返回一个受指定数组支持的固定大小的列表。(对返回列表的更改会“直接写”到数组。)此方法同
Collection.toArray()
一起,充当了基于数组的 API 与基于 collection 的 API 之间的桥梁。返回的列表是可序列化的,并且实现了RandomAccess
。此方法还提供了一个创建固定长度的列表的便捷方法,该列表被初始化为包含多个元素:
List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
-
-
参数:
-
a
- 支持列表的数组。
返回:
- 指定数组的列表视图。
-
public static <T> List<T> unmodifiableList(List<? extends T> list)
-
返回指定列表的不可修改视图。此方法允许模块为用户提供对内部列表的“只读”访问。在返回的列表上执行的查询操作将“读完”指定的列表。试图修改返回的列表(不管是直接修改还是通过其迭代器进行修改)将导致抛出
UnsupportedOperationException。
如果指定列表是可序列化的,则返回的列表也将是可序列化的。类似地,如果指定列表实现
RandomAccess
,则返回列表也将这样做。 -
-
参数:
-
list
- 将为其返回一个不可修改视图的列表。
返回:
- 指定列表的不可修改视图。
-