List集合刪除元素的正確姿式詳解

在閱讀阿里巴巴規約的時候發現有一條規約是關於List的【不要在foreach裏面進行元素的remove/add操做,remove請使用Iterator方式】。而後想起之前本身作項目的時候刪除某一元素的邏輯報下標越界錯誤,那時候記得處理是用一新的List進行存儲,而後總體從原List移除全部符合規則的元素,如今作一總結。用這個Iterator主要能夠避免下標越界或者遍歷是漏掉符合規則的下一個數據。java

先拉出來正確刪除元素的姿式。正確姿式是利用Iterator的remove方法。具體操做以下:線程

public static void main(String[] args) {
        List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
        Iterator<Integer> iterator = lists.iterator();
        while (iterator.hasNext()){
            Integer obj = iterator.next();
            if(3==obj || 4==obj){
                iterator.remove();
            }
        }
        System.out.println(lists);
    }

而後經常使用的錯誤方式有如下三種: 
第一種方式,多出現下標越界問題。這個主要緣由是由於咱們在循環遍歷時,將咱們的長度進行定值肯定。而忽略掉在知足條件時,list的長度是減小的。指針

public static void main(String[] args) {
 List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
        int size = lists.size();  // 定長設置,會形成元素下標越界,若是將for中變量直接換成lists.size()能夠嗎?
        for (int i = 0; i < size; i++) {
            if(3==lists.get(i) || 4 == lists.get(i)){
                lists.remove(i); //lists.remove(lists.get(i));
            }
        }
        System.out.println(lists);
 }

第二種方式也就是上面的註釋所說,既然會出現下標越界,那我就利用動態的大小不就能夠了,可是利用這種方法會產生另一種狀況,就是會忽略掉remove元素後面的一個元素,這個是由於刪除符合規則的元素後,list長度減一,而同時後面的元素往前補一位,形成當前i值下對應兩個元素。code

public static void main(String[] args) {
        List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
        int size = lists.size();
        for (int i = 0; i < lists.size(); i++) {
            if(3==lists.get(i) || 4 == lists.get(i)){
                lists.remove(i); //lists.remove(lists.get(i));
            }
        }
        System.out.println(lists); // 打印[1, 2, 4, 5] 此時會將4忽略掉
    }

第三種方式是利用加強FOR循環形成的。這種方式會直接給報錯:對象

ERRORInfo:
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)


public static void main(String[] args) {
        List<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        lists.add(3);
        lists.add(4);
        lists.add(5);
       for (Integer i : lists){
           if(3==i || 4==i){
               lists.remove(i);
           }
       }
        System.out.println(lists);
    }

這種狀況下。主要是集合遍歷是使用Iterator, Iterator是工做在一個獨立的線程中,而且擁有一個互斥鎖。Iterator 被建立以後會創建一個指向原來對象的單鏈索引表,當原來的對象數量發生變化時,這個索引表的內容不會同步改變,因此當索引指針日後移動的時候就找不到要迭代的對象,因此按照 fail-fast原則 Iterator 會立刻拋出java.util.ConcurrentModificationException 異常。因此 Iterator 在工做的時候是不容許被迭代的對象被改變的。索引

相關文章
相關標籤/搜索