關于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碼農志,轉載請注明原文鏈接:http://www.rzrgm.cn/zhiliu/p/18442641

浙公網安備 33010602011771號