1. 程式人生 > >關於List比較好玩的操作

關於List比較好玩的操作

刪除 bound 由於 system get ofb println 內部類 問題

  作為Java大家庭中的集合類框架,List應該是平時開發中最常用的,可能有這種需求,當集合中的某些元素符合一定條件時,想要刪除這個元素。如:

public class ListTest {  
    public static void main(String[] args) {  
       List<Integer> intList = new ArrayList<Integer>();  
       Collections.addAll(intList, 1, 2, 3, 5, 6);  
       // for循環優化寫法,只獲取一次長度  
       for(int i = 0, size = intList.size(); i < size; i++) {  
           Integer value = intList.get(i);  
           // 符合條件,刪除元素  
           if(value == 3 || value == 5) {  
              intList.remove(i);  
           }  
       }  
       System.out.println(intList);  
    }  
}  

  執行後,會拋出IndexOutOfBoundsException,因為集合中存在符合條件的元素,刪除後,集合長度動態改變,由於長度只獲取一次,發生越界,所以,去掉for循環優化,如:

public class ListTest {  
    public static void main(String[] args) {  
       List<Integer> intList = new ArrayList<Integer>();  
       Collections.addAll(intList, 1, 2, 3, 5, 6);  
       for(int i = 0; i < intList.size(); i++) {  
           Integer value = intList.get(i);  
           // 符合條件,刪除元素  
           if(value == 3 || value == 5) {  
              intList.remove(i);  
           }  
       }  
       System.out.println(intList);  
    }  
}  

  輸出:[1, 2, 5, 6],漏掉了5這個元素,當i=2的時候,值為3,刪除後,後面的元素往前補一位,這時i=3的時候,值為6,跳過了5,這樣也不行,隨後想到了用for循環增強,不顯示的操作下標,直接操作對象,如:

public class ListTest {  
    public static void main(String[] args) {  
       List<Integer> intList = new ArrayList<Integer>();  
       Collections.addAll(intList, 1, 2, 3, 5, 6);  
       for(Integer value : intList) {  
           // 符合條件,刪除元素  
           if(value == 3 || value == 5) {  
              intList.remove(value);  
           }  
       }  
       System.out.println(intList);  
    }  
}  

  執行後,會拋出ConcurrentModificationException,字面意思是並發修改異常。異常跟蹤信息如下:

  Exception inthread "main" java.util.ConcurrentModificationException

atjava.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)

at java.util.AbstractList$Itr.next(AbstractList.java:420)

at ListTest.main(ListTest.java:13)

  可以大概看出是執行到AbstractList中內部類Itr的checkForComodification方法拋出的異常,至於為什麽出現異常,這裏可以大概解釋一下。集合遍歷是使用Iterator, Iterator是工作在一個獨立的線程中,並且擁有一個互斥鎖。Iterator 被創建之後會建立一個指向原來對象的單鏈索引表,當原來的對象數量發生變化時,這個索引表的內容不會同步改變,所以當索引指針往後移動的時候就找不到要叠代的對象,所以按照 fail-fast原則 Iterator 會馬上拋出java.util.ConcurrentModificationException 異常。所以 Iterator 在工作的時候是不允許被叠代的對象被改變的。

而要解決這個問題,可以使用Iterator的remove方法,該方法會刪除當前叠代對象的同時,維護索引的一致性。如:

public class ListTest {  
    public static void main(String[] args) {  
       List<Integer> intList = new ArrayList<Integer>();  
       Collections.addAll(intList, 1, 2, 3, 5, 6);  
       Iterator<Integer> it = intList.iterator();  
       while(it.hasNext()) {  
           Integer value = it.next();  
           if(value == 3 || value == 5) {  
              it.remove();  
           }  
       }  
       System.out.println(intList);  
    }  
}  

  輸出正確結果:[1, 2, 6]。

不使用叠代器的解決方案就是,自己維護索引,刪除一個元素後,索引-1,如:

public class ListTest {  
    public static void main(String[] args) {  
       List<Integer> intList = new ArrayList<Integer>();  
       Collections.addAll(intList, 1, 2, 3, 5, 6);  
       for(int i = 0; i < intList.size(); i++) {  
           Integer value = intList.get(i);  
           if(value == 3 || value == 5) {  
              intList.remove(i);  
              i--;  
           }  
       }  
        System.out.println(intList);  
    }  
}  

  輸出正確結果:[1, 2, 6]。

還有種取巧的方式是從最後一個元素開始遍歷,符合條件的刪除,如:

public class ListTest {  
    public static void main(String[] args) {  
       List<Integer> intList = new ArrayList<Integer>();  
       Collections.addAll(intList, 1, 2, 3, 5, 6);  
       for(int i = intList.size() - 1; i >= 0; i--) {  
           Integer value = intList.get(i);  
           if(value == 3 || value == 5) {  
              intList.remove(i);  
           }  
       }  
        System.out.println(intList);  
    }  
} 

輸出正確結果:[1, 2, 6]。

最後,Java集合類框架真是大大方便了開發,不用自己去維護數組,隨時擔心著越界等問題。當然List的實現類對插入、刪除的效率不太一樣,這取決於其實現的數據結構,是選擇刪除,還是選擇新建個集合,這裏就不做討論了。

關於List比較好玩的操作