关于Arrays.asList返回的List无法新增和删除?
一、问题重现:一行代码引发的异常
日常开发中,我们常通过Arrays.asList()将数组转为List,但调用add/remove时会抛出异常:
Integer[] array = {1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(array);
list.add(11); // 运行报错:UnsupportedOperationException
这是为什么?同样是List接口,为什么new ArrayList<>()能正常增删,而这里却不行?
二、源码揭秘:两个"ArrayList"的差异
1. 返回的不是普通ArrayList
Arrays.asList()返回的是java.util.Arrays的静态内部类ArrayList,而非我们常用的java.util.ArrayList:
// Arrays类的静态内部类(简化版)
private static class ArrayList<E> extends AbstractList<E> {
private final E[] a; // 持有原数组引用(final修饰)
ArrayList(E[] array) {
    a = Objects.requireNonNull(array); // 直接引用原数组,不做拷贝
}
// 只实现了get/set/size等读取和修改元素的方法
@Override
public E get(int index) { return a[index]; }
@Override
public E set(int index, E element) { /* 修改元素 */ }
@Override
public int size() { return a.length; }
// 关键:未重写add()和remove()方法!
}
2. 为什么不能新增/删除?
Arrays内部类ArrayList继承了AbstractList,但没有实现add/remove等修改集合结构的方法。而AbstractList的默认实现就是直接抛异常:
public abstract class AbstractList<E> {
// 未被重写时,调用add就会抛异常
public void add(int index, E element) {
    throw new UnsupportedOperationException();
}
// remove同理
public E remove(int index) {
    throw new UnsupportedOperationException();
}
}
对比之下,我们常用的java.util.ArrayList重写了这些方法,通过动态扩容(拷贝新数组) 实现元素的新增和删除,因此支持修改操作。
三、解决方案:获取可修改的List
如果需要对转换后的List进行增删操作,推荐两种方案:
方案1:用ArrayList包装(最常用)
通过java.util.ArrayList的构造方法,将Arrays.asList()的结果传入。这个过程会拷贝原数组元素,生成独立的可变List:
Integer[] array = {1, 2, 3};
// 包装后得到可修改的List
List<Integer> mutableList = new ArrayList<>(Arrays.asList(array));
mutableList.add(4); // 正常执行,无异常
方案2:Stream流转换(指定具体实现类)
Java 8+的Stream流可以转换集合,但需注意:Collectors.toList()在不同JDK版本中返回的实现类不同(可能是可变或不可变)。若要确保可修改,建议显式指定ArrayList:
// 显式指定用ArrayList接收,确保可修改
List<Integer> mutableList = Arrays.stream(array)
    .collect(Collectors.toCollection(ArrayList::new));
四、扩展:Stream流转换的List也可能不可修改
很多人以为Stream流转换的List一定可以修改,这其实是个误区。Collectors.toList()的返回值在JDK 8中是ArrayList(可变),但在JDK 9及以上版本中,可能返回不可修改的集合(如java.util.ImmutableCollections$ListN):
// JDK 11环境下可能出现的情况
List<Integer> list = Arrays.stream(array).collect(Collectors.toList());
list.add(11); // 可能抛UnsupportedOperationException
原因:JDK 9+为了优化性能,默认返回不可变集合(节省内存、线程安全)。若需确保可修改,必须像方案2那样显式指定ArrayList作为容器。
五、注意事项
- 
原数组与List的关联性
Arrays.asList()返回的List直接引用原数组,修改原数组会同步影响List:array[0] = 100; System.out.println(list.get(0)); // 输出100(而非原1) - 
避免直接使用不可变List
若仅需遍历或修改元素(set),Arrays.asList()完全可用;若需增删元素,必须通过上述方案转换为可变List。 
总结
Arrays.asList()返回的是Arrays内部类ArrayList,未实现add/remove,因此不可增删;- 转换为可修改List的可靠方式:
new ArrayList<>(Arrays.asList(array))或Stream流指定ArrayList; - JDK 9+中
Collectors.toList()可能返回不可变集合,需显式指定实现类。 
本文来自博客园,作者:Liberty码农志,转载请注明原文链接:https://www.cnblogs.com/zhiliu/p/18442641

                
            
        
浙公网安备 33010602011771号