天天看點

小心!"數組"轉"集合"的這幾個隐藏"bug"

先給不熟悉的兄弟們科普一下:

Array.asList()方法用于将數組轉化為集合

對于經常做資料處理的朋友來說

應該并不陌生

不過話說回來

這個方法有幾個隐藏的"坑"

可能有兄弟會中招

咱們接下來就一探究竟

聽說點贊分享效果更佳呢!!

坑一:不能直接轉換基本資料類型的數組

錯誤案例:

//定義基本資料類型int類數組
int[] arr = {1, 2, 3};
//使用Array.asList()方法轉換為集合
List list = Arrays.asList(arr);
//輸出轉換之後的集合資訊
log.info("list:{} size:{}", list, list.size());           

複制

期望輸出:

list:[1, 2, 3] size:3           

複制

控制台實際輸出:

list:[[I@1c53fd30] size:1           

複制

很明顯隐藏的”坑“出現了,

擁有三個元素的數組在轉換之後隻剩一個元素且資料類型有問題。

原因分析:

雖然int可以裝箱為包裝類integer,但int數組則無法整體裝箱成integer數組。

脫坑方案:

1、Java8以上提供了Arrays.stream方法強制轉換

int[] arr1 = {1, 2, 3};
List list1 = Arrays.stream(arr1).boxed().collect(Collectors.toList());
log.info("list:{} size:{}", list1, list1.size());           

複制

2、直接使用包裝類integer定義數組

Integer[] arr2 = {1, 2, 3};
List list2 = Arrays.asList(arr2);
log.info("list:{} size:{}", list2, list2.size());           

複制

修改之後的控制台輸出:

list:[1, 2, 3] size:3           

複制

得到了我們期望的結果,第一個坑我們就脫坑成功啦!

兄弟不要吝啬你的點贊哦!是我繼續輸出的動力,我們繼續脫坑:

坑二:轉換之後的集合無法增删元素

錯誤案例:

//這次我們用引用類String數組
String[] arr = {"1", "2", "3"};
List list = new ArrayList(Arrays.asList(arr));
try {
//嘗試向轉換後的list追加元素
list.add("5");
} catch (Exception ex) {
ex.printStackTrace();
}
//轉換之後,修改原數組的值
arr[1] = "4";
//輸出原數組、轉換後的集合
log.info("arr:{} list:{}", Arrays.toString(arr), list);           

複制

期望輸出:

arr:[1, 4, 3] list:[1, 2, 3, 5]           

複制

控制台實際輸出:

//首先是list追加元素的異常
java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at org.geekbang.time.commonmistakes.collection.aslist.AsListApplication.wrong2(AsListApplication.java:41)
at org.geekbang.time.commonmistakes.collection.aslist.AsListApplication.main(AsListApplication.java:15)
//元素輸出
arr:[1, 4, 3] list:[1, 4, 3]           

複制

根據控制台輸出來看,

我們不僅向list追加元素失敗,

我們對原數組中元素的修改也影響到了集合list,

這就是第三個坑點:

坑三:對原始數組的修改會影響轉換之後的List

原因分析:

其實Arrays.asList方法傳回的List并不是我們期望的java.util.ArrayList,而是Arrays的内部類ArrayList。

兩者的差別在于,ArrayList内部類繼承自AbstractList類,并沒有覆寫父類的add方法,是以就産生了上面的異常。

至于第三個坑點則是因為ArrayList直接使用了原始的數組,是以會産生互相共享數組的效果。

如果我們把通過Arrays.asList獲得的List交給其他方法處理,很容易因為共享了數組,互相修改産生隐式的“bug”。

這種問題是很難找原因的,要特别小心。

脫坑方案:

方法其實不難猜想,

我們隻需要用一個真正的java.util.ArrayList來存放轉換之後的list即可

String[] arr = {"1", "2", "3"};
//用java.util.ArrayList接收轉換後的list
List list = new ArrayList(Arrays.asList(arr));
arr[1] = "4";
try {
list.add("5");
} catch (Exception ex) {
ex.printStackTrace();
}
log.info("arr:{} list:{}", Arrays.toString(arr), list);           

複制

修改之後的控制台輸出:

arr:[1, 4, 3] list:[1, 2, 3, 5]           

複制

輸出符合我們的預期。

我們new的ArrayList既可以做add操作、又和之前的數組實作了分離。

這樣就很好的解決了問題!

end