java.lang.UnsupportedOperationException问题探究

异常代码

1
2
3
4
5
6
7
List<Integer> list = Arrays.asList(1,2,3);
list.add(4);
list.remove(1);
list.clear();

运行这段代码,执行的三个方法都会抛异常:java.lang.UnsupportedOperationException

原因分析

跟踪源码,Arrays中asList实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Returns a fixed-size list backed by the specified array. (Changes to
* the returned list "write through" to the array.) This method acts
* as bridge between array-based and collection-based APIs, in
* combination with {@link Collection#toArray}. The returned list is
* serializable and implements {@link RandomAccess}.
*
* <p>This method also provides a convenient way to create a fixed-size
* list initialized to contain several elements:
* <pre>
* List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
* </pre>
*
* @param <T> the class of the objects in the array
* @param a the array by which the list will be backed
* @return a list view of the specified array
*/
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}

乍一看确实返回了一个ArrayList,这么会不支持添加、删除、清空操作呢?再跟下ArrayList代码发现,这个ArrayList居然是在Arrays中定义的静态内部类:

1
2
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable

而我们平时用的java.util.ArrayList是这个:

1
2
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

两者区别在于Arrays中的ArrayList并未实现add、remove方法,调用这两个方法的时候实际是调用了其父类AbstractList的add、remove方法,AbstractList中直接抛了异常:

1
2
3
4
5
6
7
8
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
}

而clear方法内部最终还是调用了remove来实现,所以同样会抛异常

解决方法

JDK当初这样设计估计只是简单提供一个可读权限集合,所以使用Arrays数组转集合时,如果会对集合进行添加或者删除时,可以将引用转移到其他地方:

1
2
List list = Arrays.asList(T ... );
List newList = new ArrayList(list);