调用ArrayList的add方法抛异常UnsupportedOperationException
调用ArrayList的add方法抛异常UnsupportedOperationException
对于一些想要把数组转成List的需求,可能会使用到Arrays.asList()获取List对象,但是这里面也存在一些问题。
示例代码如下
void test1(){
List<Object> list = Arrays.asList();
list.add("hello");
}
执行后报错信息为
java.lang.UnsupportedOperationException
at java.base/java.util.AbstractList.add(AbstractList.java:153)
at java.base/java.util.AbstractList.add(AbstractList.java:111)
at com.heima.item.test.test.test1(test.java:15)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
......
在上述代码中,list.add("hello")执行报错,异常为java.lang.UnsupportedOperationException,通过查看Arrays里的asList()方法可以看到如下信息
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
这边是new了一个新的ArrayList对象,有人可能以为这是我们所熟悉的那个ArrayList,但是其实不是,这是【java.util.Arrays.ArrayList】,而我们常用的ArrayList是【java.util.ArrayList】在Arrays的源码里面可以看到压根没有导入我们熟悉的那个ArrayList,而是定义了一个内部类。简单来说这是两个类,只是名字相同了,恰好都是ArrayList。
这个内部类是直接继承了AbstractList,它并没有重写add方法,所以我们调了add方法其实是调的AbstractList里的add方法,AbstractList里的add方法源码为
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
原因很明显,不重写的话一调就抛出异常UnsupportedOperationException。
不止add方法,set,remove这些方法也不能通过Arrays.asList得到的对象调用,具体可以参考Arrays和AbstractList这两个类的源码。
另辟蹊径:
方法一
对于想要通过asList来获取List对象,又想调用add方法的,可以使用下列方式得到java.util.ArrayList对象,没错这正是我们常用的List实例对象。
void test2(){
String [] strs = {"AAA", "BBB", "CCC"};
List<String> list1 = Arrays.asList(strs);
ArrayList<String> list2 = new ArrayList(list1);
list2.add("XXX");
list2.forEach(System.out::println);
}
通过这种方式,可以正常add元素进入list,遍历打印出来的结果如下
AAA
BBB
CCC
XXX
方法二
避免使用Arrays.asList,而是使用Collections.addAll来帮助我们把数组里的元素全部添加到List对象里。
void test3(){
String [] strs = {"AAA", "BBB", "CCC"};
List<String> list1 = Arrays.asList(strs);
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2, strs);
list2.add("YYY");
list2.forEach(System.out::println);
}
遍历打印出来的结果如下
AAA
BBB
CCC
YYY
方法三
遍历复制元素。把java.util.Arrays.ArrayList里的元素遍历,然后一个个添加进入自己创建的java.util.ArrayList实例里。
void test4(){
String [] strs = {"AAA", "BBB", "CCC"};
List<String> list1 = Arrays.asList(strs);
ArrayList<String> list2 = new ArrayList<>();
list1.forEach(e -> {
list2.add(e);
});
list2.add("ZZZ");
list2.forEach(System.out::println);
}
遍历打印出来的结果如下
AAA
BBB
CCC
ZZZ
方法四
遍历复制元素。把java.util.Arrays.ArrayList里的所有元素一次性添加进入自己创建的java.util.ArrayList实例里。
void test5(){
String [] strs = {"AAA", "BBB", "CCC"};
List<String> list1 = Arrays.asList(strs);
ArrayList<String> list2 = new ArrayList<>();
list2.addAll(list1);
list2.add("OOO");
list2.forEach(System.out::println);
}
遍历打印出来的结果如下
AAA
BBB
CCC
OOO
方法五
直接创建java.util.ArrayList对象,使用for循环遍历数组然后add元素。
其他方法
还有一些没有介绍到的方式,比如List.copyOf,Stream API之类等等,最后都能得到想要的对象,但是不够简单。比较推荐使用常见的这几种方式。