一起來愉快的踩坑之旅——List

一起來愉快的踩坑之旅——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.ArraysArrayListArrayList (表示內部類的意思,下面的源碼是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());
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章