全是坑!慎用 Arrays.asList
面試題庫 | 自研短鏈項目 | 簡歷修改&模擬面試 | 招聘信息
Java 8 提供的 Stream 流式處理大大減少了集合類各種操作(投影、過濾、轉(zhuǎn)換)的代碼量,用起來非常香,所以在實際業(yè)務開發(fā)中,我們常常會把原始的數(shù)組轉(zhuǎn)換為 List 類數(shù)據(jù)結構,使得其可以用上 Stream 流操作。
Arrays.asList 方法應該是各位最常用的數(shù)組一鍵轉(zhuǎn)換為 List 的方法了,但這個方法有幾個坑,如果不了解的話,排查 Bug 可能會比較困難:
- 坑 1:不能直接使用 Arrays.asList 來轉(zhuǎn)換基本類型數(shù)組
- 坑 2:Arrays.asList 返回的 List 不支持增刪操作
- 坑 3:對原始數(shù)組的修改會影響 Arras.asList 返回的那個 List
第一個坑
在如下代碼中,我們初始化三個數(shù)字的 int[]數(shù)組,然后使用 Arrays.asList 把數(shù)組轉(zhuǎn)換為 List:
但,這樣初始化的 List 并不是我們期望的包含 3 個數(shù)字的 List,輸出結果如下:
可以發(fā)現(xiàn),這個 List 包含的其實是一個 int 數(shù)組,整個 List 的元素個數(shù)是 1,元素類型是整數(shù)數(shù)組。
其原因是,只能是把單個 int 類型裝箱為 Integer,不能把 int 數(shù)組裝箱為 Integer 數(shù)組。Arrays.asList 方法傳入的是一個泛型 T 類型可變參數(shù),所以 int 數(shù)組實際上是被整體看成一個對象作為泛型類型 T:
以上,就是第一個坑:不能直接使用 Arrays.asList 來轉(zhuǎn)換基本類型數(shù)組。直接遍歷這樣的 List 必然會出現(xiàn) Bug,修復方式有兩種:
-
最簡單的,直接把數(shù)組聲明為包裝類型,不要用 int 這種基本類型

-
如果使用 Java8 以上版本可以使用 Arrays.stream 方法來轉(zhuǎn)換,stream 流提供了 boxed 裝箱操作:

第二個坑
把三個字符串 1、2、3 構成的字符串數(shù)組,使用 Arrays.asList 轉(zhuǎn)換為 List 后,然后為 List 增加一個字符串 4:
結果如下,為 List 新增字符串 4 的操作失敗了,報錯 UnsupportedOperationException:
第二個坑:Arrays.asList 返回的 List 不支持增刪操作。
因為 Arrays.asList 返回的 List 并不是我們期望的 java.util.ArrayList,而是 Arrays 的內(nèi)部類 ArrayList:
ArrayList 內(nèi)部類繼承自 AbstractList 類,并沒有覆寫父類的 add 方法,而父類中 add 方法的實現(xiàn),就是拋出 UnsupportedOperationException:
第三個坑
把三個字符串 1、2、3 構成的字符串數(shù)組,使用 Arrays.asList 轉(zhuǎn)換為 List 后,然后修改原字符串數(shù)組的第一個元素為 0:
輸出如下,把原始數(shù)組的第一個元素從 1 修改為 0 后,asList 獲得的 List 中的第一個元素也被修改為 0 了:
第三個坑:對原始數(shù)組的修改會影響 Arras.asList 返回的那個 List。
看一下 ArrayList 的實現(xiàn),可以發(fā)現(xiàn) ArrayList 其實是直接使用了原始的數(shù)組。所以,我們要特別小心,把通過 Arrays.asList 獲得的 List 交給其他方法處理,很容易因為共享數(shù)組,相互修改而產(chǎn)生 Bug。
第二個坑和第三個坑的本質(zhì)原因是一樣的,都是由于數(shù)組共享導致的問題,所以解決方式比較簡單,重新 new 一個 ArrayList 初始化 Arrays.asList 返回的 List 即可:
修改后的代碼實現(xiàn)了原始數(shù)組和 List 的解耦,不再相互影響。同時,因為操作的是真正的 ArrayList,add 也不再報錯:
面試題庫 | 自研短鏈項目 | 簡歷修改&模擬面試 | 招聘信息
