早上到公司,刚到工位,测试同事就跑来说"功能不行了,报服务器异常了,咋回事";我一脸蒙,早饭都顾不上吃,要来了测试账号复现了一下,然后仔细观察测试服务器日志,发现报了一个
java.lang.UnsupportedOperationException
异常
经排查发现,是将一个枚举类中两个元素,用
Arrays.asList
生成一个List集合,并且将这个集合当作一个方法的参数传递,在该方法中,正好使用此List进行了add
方法的操作,导致异常发生了
Arrays.asList
使用此方式生成的List集合为什么不能执行add方法 ? 先来看下源码
coffeescript
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a); // ArrayList 是静态内部类
}
/**
* @serial include
*/
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a; //被final修饰,不可变
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
@Override
public int size() {
return a.length;
}
.......... 省略,可自行去看源码....
}
从源码可见,Arrays.asList
实际上也是new
了一个 ArrayList
,但是此处的ArrayList是Arrays这个类中的静态内部类
,该内部类中的变量a 是被final
修饰,说明变量a是不可变的,数据不可被修改
coffeescript
/**
* {@inheritDoc}
*
* <p>This implementation always throws an
* {@code UnsupportedOperationException}.
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
其次,内部类ArrayList中并没有add的方法,而是使用了继承类AbstractList
中add方法,该方法没有被重写
,所以直接就抛了UnsupportedOperationException
异常,正好对应上了
直接使用new
clike
List<String> list= new ArrayList<>();
list.add("王五");
首先该ArrayList 是包java.util
下的类,虽然也继承了抽象类AbstractList
,但是重写了抽象类AbstractList中的add方法
coffeescript
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
正是因为重写了add
方法,所以才没有使用抽象类AbstractList
中抛异常的add方法
如何使用Arrays.asList创建的List可以正常执行add操作?
上面分析了原因,因为Arrays中的静态内部类ArrayList未重写add方法
,如果执行的add方法是重写后的,是否就可以解决? 可以将代码优化成下面的方式
clike
List<String> list1 = Arrays.asList("张三", "李四");
try {
list1.add("王五");
} catch (UnsupportedOperationException e) {
System.out.println("oh, 报错了=" + e.toString());
}
//改良方式
List<String> list2 = new ArrayList<>(Arrays.asList("张三", "李四"));
list2.add("王五");
System.out.println("正常执行=" + list2);
执行效果