10_集合類 list操作的坑

Arrays.asList把數據轉換爲List的三個坑

1, 不能直接使用Arrays.asList來轉換基本類型數
這個List包含的其實是一個int數組,整個List的元素個數是元素類型是整數數組。
int[] arr = {1, 2, 3};
List list = Arrays.asList(arr);   // idea中顯示  List<int[]> ints = Arrays.asList(arr);

# 修改  使用包裝類型
 Integer[] array = new Integer[]{1,2};
  List<Integer> integers = Arrays.asList(array);
2, Arrays.asList返回的List**不支持增刪操作**
,Arrays.asList返回的List並不是我們期望的java.util.ArrayList,**而是Arrays的內部類ArrayList**。ArrayList內部類繼承自AbstractList類,並沒有覆寫父類的add方法,而父類中add方法的實現,就是拋出UnsupportedOperationException。

優化: 聲明一個新的List

String[] arr = {"1", "2", "3"};
List list = new ArrayList(Arrays.asList(arr));
3, 使用List.subList進行切片操作居然會導致OOM?
List<Integer> list = IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toList());
List<Integer> subList = list.subList(1, 4);

ArrayList的subList 在list有個內部類, 這個sublist沒有創建新的list, 直接用的list。 所以修改sublist和list會相互影響。

解決方法:
1, 不直接使用subList方法返回的SubList,而是重新使用new ArrayList,在構造方法傳入SubList,來構建一個獨立的ArrayList;
2, 對於Java 8使用Stream的skip和limit API來跳過流中的元素,以及限制流中元素的個數,同樣可以達到SubList切片的目的

//方式一:
List<Integer> subList = new ArrayList<>(list.subList(1, 4));
//方式二:
List<Integer> subList = list.stream().skip(1).limit(3).collect(Collectors.toList());

在這裏插入圖片描述

4,asList 數組與返回的list共享數據
 Integer[] integers = new Integer[3];
        integers[0] = 1;
        integers[1] = 2;
        List<Integer> integers1 = Arrays.asList(integers);
        integers[2] = 3 ;
        Arrays.stream(integers).forEach(System.out::println);
        System.out.println("======>>>>>>");
        integers1.forEach(System.out::println);

在這裏插入圖片描述

一定要讓合適的數據結構做合適的事情

ArrayList和HashMap查找對比

  1. 要對大List進行單值搜索的話,可以考慮
    使用HashMap,其中Key是要搜索的值,Value是原始對象,會比使用ArrayList有非常明顯的性能優勢。
  2. ArrayList在內存佔用上性價比很高,77%(大約)是實際的數據,而HashMap的“含金量”只有22%(大約)。

LinkedList和ArrayList插入和查詢對比

  1. 書本上的解釋:

    對於數組,隨機元素訪問的時間複雜度是O(1),元素插入操作是O(n); 查詢快
    對於鏈表,隨機元素訪問的時間複雜度是O(n),元素插入操作是O(1)。 插入快

  2. 實際: 數組和鏈表 查詢和插入都比鏈表快。

    插入操作的時間複雜度是O(1)的前提是,你已經有了那個要插入節點的指針。但,在實現的時候,我們需要先通過循環獲取到那個節點的Node,然後再執行插入操作。前者也是有開銷的,不可能只考慮插入操作本身的代價:
    在這裏插入圖片描述
    總結:
    1, Arrays.asList得到的是Arrays的內部類ArrayList,List.subList得到的是ArrayList的內部類SubList,不能把這兩個內部類轉換爲ArrayList使用。
    2, Arrays.asList直接使用了原始數組,可以認爲是共享“存儲”,而且不支持增刪元素;List.subList直接引用了原始的List,也可以認爲是共享“存儲”,而且對原始List直接進行結構性修改會導致SubList出現異常。
    3, 對Arrays.asList和List.subList容易忽略的是,新的List持有了原始數據的引用,可能會導致原始數據也無法GC的問題,最終導致OOM

問題:

  1. 調用類型是Integer的ArrayList的remove方法刪除元素,傳入一個Integer包裝類的數字和傳入一個int基本類型的數字,結果一樣嗎?
  2. 循環遍歷List,調用remove方法刪除元素,往往會遇到ConcurrentModificationException異常,原因是什麼,修復方式又是什麼呢?

1、使用 ArrayList 的 remove方法,如果傳參是 Integer類型的話,表示的是刪除元素,如果傳參是int類型的話,表示的是刪除相對應索引位置的元素。;兩個都需要進行數組拷貝,是通過System.arraycopy進行的
2、以foreach爲例說,遍歷刪除實質是變化爲迭代器實現,不管是迭代器裏面的remove()還是next()方法,都會checkForComodification();而這個方法是判斷modCount和expectedModCount是否相等,這個modCount是這個list集合修改的次數,每一次add或者remove都會增加這個變量,然後迭代器每次去next或者去remove的時候檢查checkForComodification();發現expectedModCount(這個迭代器修改的次數)和modCount(這個集合實際修改的次數)不相等,就會拋出ConcurrentModificationException,迭代器裏面沒有add方法,用迭代器時,可以刪除原來集合的元素,但是!一定要
用迭代器的remove方法而不是集合自身的remove方法,否則拋異常。

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