调用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之类等等,最后都能得到想要的对象,但是不够简单。比较推荐使用常见的这几种方式。

posted @ 2024-08-26 23:18  比花花解语  阅读(9)  评论(0编辑  收藏  举报