Java中Arrays.asList() 的不可變陷阱
一、問題現(xiàn)象:無(wú)法修改的集合
當(dāng)開發(fā)者使用 Arrays.asList() 轉(zhuǎn)換數(shù)組為集合時(shí),嘗試添加/刪除元素會(huì)拋出異常:
String[] arr = {"Java", "Python", "Go"};
List<String> list = Arrays.asList(arr);
// 嘗試添加元素
list.add("JavaScript"); // 拋出 UnsupportedOperationException
// 嘗試刪除元素
list.remove(0); // 同樣拋出異常
控制臺(tái)報(bào)錯(cuò):
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.add(AbstractList.java:148) at java.util.AbstractList.add(AbstractList.java:108)
二、原理剖析:為什么不可變?
2.1 源碼分析
// Arrays.java
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a); // 注意:此ArrayList非java.util.ArrayList
}
// Arrays內(nèi)部的私有靜態(tài)類
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable {
private final E[] a; // final修飾的數(shù)組!
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
// 未重寫add/remove方法(繼承AbstractList的默認(rèn)實(shí)現(xiàn))
}
// AbstractList.java
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
2.2 設(shè)計(jì)本質(zhì)
| 特性 | Arrays.ArrayList | java.util.ArrayList |
|---|---|---|
| 存儲(chǔ)結(jié)構(gòu) | 包裝原始數(shù)組(final) | 動(dòng)態(tài)數(shù)組(Object[] elementData) |
| 長(zhǎng)度是否可變 | ? 固定長(zhǎng)度 | ? 動(dòng)態(tài)擴(kuò)容 |
| 是否支持增刪 | ? 拋出異常 | ? 正常操作 |
| 內(nèi)存占用 | 更低(直接引用原數(shù)組) | 更高(拷貝數(shù)據(jù)) |
關(guān)鍵限制:
- 底層數(shù)組由
final修飾,無(wú)法擴(kuò)容 - 未重寫
add()、remove()等修改方法 - 繼承
AbstractList的默認(rèn)實(shí)現(xiàn)(直接拋異常)
三、解決方案:創(chuàng)建真正的可變集合
3.1 使用 new ArrayList() 包裝(推薦)
String[] arr = {"Java", "Python", "Go"};
// 方案1:構(gòu)造方法包裝
List<String> mutableList = new ArrayList<>(Arrays.asList(arr));
// 方案2:Java 8+ Stream API
List<String> mutableList = Arrays.stream(arr)
.collect(Collectors.toList());
優(yōu)點(diǎn):代碼簡(jiǎn)潔,兼容所有Java版本
3.2 Java 9+ 的 List.of() 替代方案
// 不可變集合(Java 9+)
List<String> immutableList = List.of("Java", "Python", "Go");
// 需要可變時(shí)顯式轉(zhuǎn)換
List<String> mutableList = new ArrayList<>(immutableList);
注意:List.of() 創(chuàng)建的集合完全不可變(增刪改均拋異常)
3.3 特殊場(chǎng)景:修改原始數(shù)組
若只需修改元素值(不增刪元素),可操作原始數(shù)組:
String[] arr = {"Java", "Python", "Go"};
List<String> list = Arrays.asList(arr);
// 修改元素(允許!)
list.set(1, "C++");
System.out.println(Arrays.toString(arr)); // [Java, C++, Go]
// 原始數(shù)組同步變化
arr[0] = "Rust";
System.out.println(list); // [Rust, C++, Go]
原理:集合直接引用原始數(shù)組,數(shù)據(jù)共享
四、最佳實(shí)踐與總結(jié)
4.1 使用場(chǎng)景決策樹
需要集合操作嗎? ├── 是 → 需要增刪元素? │ ├── 是 → 使用 new ArrayList<>(Arrays.asList(...)) │ └── 否 → 只需讀/改元素 → Arrays.asList() 或 List.of() └── 否 → 直接使用原始數(shù)組
4.2 各方案特性對(duì)比
| 方法 | 可變性 | 線程安全 | 內(nèi)存開銷 | Java版本要求 |
|---|---|---|---|---|
| Arrays.asList() | 部分? | 非安全 | 低 | 1.2+ |
| new ArrayList<>(...) | ? | 非安全 | 中 | 1.2+ |
| Arrays.stream().collect() | ? | 非安全 | 中 | 8+ |
| List.of() | ? | 安全 | 低 | 9+ |
4.3 終極原則
明確需求:區(qū)分"只讀" vs "可變"場(chǎng)景
優(yōu)先新語(yǔ)法:Java 8+ 項(xiàng)目多用 Stream API
防御式編程:
// 返回不可修改視圖(避免誤操作)
public List<String> getLanguages() {
return Collections.unmodifiableList(Arrays.asList("Java", "Python"));
} 到此這篇關(guān)于Java中Arrays.asList() 的不可變陷阱的文章就介紹到這了,更多相關(guān)Java Arrays.asList() 陷阱內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java硬幣翻轉(zhuǎn)倍數(shù)遞增試算實(shí)例
這篇文章主要介紹了Java硬幣翻轉(zhuǎn)倍數(shù)遞增試算實(shí)例,有需要的朋友可以參考一下2013-12-12
Java使用正則表達(dá)式判斷獨(dú)立字符的存在(代碼示例)
通過使用正則表達(dá)式,我們可以更加靈活地判斷字符串中是否包含特定的字符,并且可以控制匹配的條件,如獨(dú)立的字符,這為我們處理字符串提供了更多的選擇和功能,這篇文章主要介紹了Java使用正則表達(dá)式判斷獨(dú)立字符的存在,需要的朋友可以參考下2023-10-10
SpringBoot單元測(cè)試沒有執(zhí)行的按鈕問題及解決
這篇文章主要介紹了SpringBoot單元測(cè)試沒有執(zhí)行的按鈕問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
Java Map 按照Value排序的實(shí)現(xiàn)方法
Map是鍵值對(duì)的集合接口,它的實(shí)現(xiàn)類主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。這篇文章主要介紹了Java Map 按照Value排序的實(shí)現(xiàn)方法,需要的朋友可以參考下2016-08-08
SpringBoot實(shí)現(xiàn)過濾敏感詞的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用SpringBoot實(shí)現(xiàn)過濾敏感詞功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手嘗試一下2022-08-08
Java While循環(huán) do-while循環(huán)用法
循環(huán)語(yǔ)句就是讓計(jì)算機(jī)根據(jù)條件做循環(huán)計(jì)算,在條件滿足時(shí)繼續(xù)循環(huán),條件不滿足時(shí)退出循環(huán),需要的朋友可以參考下2020-11-11

