一起來愉快的踩坑之旅——List
由於在平時編程中常用到List,但是List裏面還有很多不爲人知的坑,下面就來總結下常見的一些坑
Arrays$ArrayList到底你是誰
問題代碼
public static void main(String[] args) {
String[] arrays ={"1","2","3"};
List<String> list = Arrays.asList(arrays);
list.add("4");
}
分析
看似很簡單的代碼,使用Arrays.asList將一個數組轉化爲List然後再添加一個元素,十分正常但是會拋出異常如下:
爲啥我返回的ArrayList添加一個元素會報錯?決定Debug進去看一下:
原來用Arrays.aslist得到的不是一個ArrayList而是一個Arrays的一個內部類
add和remove方法實際都來自AbstractList而java.utilArrays$ArrayList並沒有重寫父類的方法,而會拋出UnsupportedOperationException
。這就是爲啥不支持增刪的原因。
java.util.Arrays表示內部類的意思,下面的源碼是Arrays內部類*ArrayList 的類型定義源碼,在**java.util.Arrays.class文件中***)
list互相影響?
上面使用Arrays.asList(arrays)獲取,除了不支持增刪改查還會有一個大問題,就是原數組和新生成的內部數組會互相影響
public static void main(String[] args) {
String[] arrays ={"1","2","3"};
List<String> list = Arrays.asList(arrays);
list.set(0,"a");
arrays[2] = "c";
System.out.println("arrays:"+Arrays.toString(arrays));
System.out.println("list"+list);
}
結果:
可以看到,不管是修改原數組還是新的list集合兩者都會互相影響。
是因爲這個方法實現的時候使用了原始的數組
解決問題
-
套娃一層ArrayList
List<String> list = new ArrayList<>(Arrays.asList(arrays));
但是十分的麻煩
-
谷歌提供的Guava Lists 方法
List<String> list = Lists.newArrayList(arrays);
這兩種方法都可以將新的List和原始數組解耦,不影響互相使用,同時由於生成的是正在的ArrayList,可以正常使用
與Arrays.asList一樣的subList方法產生的新集合也會和原始的List集合互相影響。由於SubList內部有一個parent字段保存了最原始的List。
而且由於SubList還在引用原始的List所以容易造成OOM問題。由於每個SubList都會強引用一個10萬個元素的原始List導致GC無法回收
foreach 增加/刪除元素大坑
代碼:
public static void main(String[] args) {
String[] arrays = {"1","2","3"};
List<String> list = new ArrayList<String>(Arrays.asList(arrays));
for(String str:list){
if (str.equals("1")){
list.remove(str);
}
}
}
看似很正常,然是卻報錯
可以清楚的看到程序的最終錯誤是由ArrayList$Itr.next處拋出,但是我們沒有調用該方法,實際上是由於foreach這種方法是一種語法糖,其實際上就是Iterator迭代器實現方法。
解決方法
-
使用Iterator 的remove方法刪除元素
public static void main(String[] args) { String[] arrays = {"1","2","3"}; List<String> list = new ArrayList<String>(Arrays.asList(arrays)); Iterator<String> iterator =list.iterator(); while (iterator.hasNext()){ String str = iterator.next(); if("1".equals(str)){ iterator.remove(); } } list.toString(); }
-
JDK1.8 List removeIf
public static void main(String[] args) { String[] arrays = {"1","2","3"}; List<String> list = new ArrayList<String>(Arrays.asList(arrays)); list.removeIf(str->str.equals("1")); System.out.println(list.toString()); }
t(arrays));
list.removeIf(str->str.equals(“1”));
System.out.println(list.toString());
}