作爲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);
- }
- }
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);
- }
- }
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);
- }
- }
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.AbstractListItr.checkForComodification(AbstractList.java:449)</p><p> 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);
- }
- }
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);
- }
- }
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);
- }
- }
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的實現類對插入、刪除的效率不太一樣,這取決於其實現的數據結構,是選擇刪除,還是選擇新建個集合,這裏就不做討論了。
本文來自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/9347357。