一、List周遊過程中删除元素
使用索引下标周遊的方式
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(2);
list.add(3);
list.add(4);
for (int i = 0; i < list.size(); i++) {
if(2 == list.get(i)){
list.remove(i);
}
System.out.println(list.get(i));
}
System.out.println("list=" + list.toString());
}
複制
輸出結果:
1
2
3
4
list=[1, 2, 3, 4]
複制
這種方式的問題在于,删除某個元素後,list的大小發生了變化,而你的索引也在變化,是以會導緻你在周遊的時候漏掉某些元素。比如當你删除第1個元素後,繼續根據索引通路第2個元素時,因為删除的關系後面的元素都往前移動了一位,是以實際通路的是第3個元素。是以,這種方式可以用在删除特定的一個元素時使用,但不适合循環删除多個元素時使用。
使用增強for循環的方式
public static void listIterator2(){
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(2);
list.add(3);
list.add(4);
for (int value : list) {
if(2 == value){
list.remove(value);
}
System.out.println(value);
}
System.out.println("list=" + list.toString());
}
複制
輸出結果:
Exception in thread "main" 1
2
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at test.ListIterator.listIterator2(ListIterator.java:39)
at test.ListIterator.main(ListIterator.java:10)
複制
說明:
jdk中對ConcurrentModificationException的描述:
public class ConcurrentModificationException extends
RuntimeException當方法檢測到對象的并發修改,但不允許這種修改時,抛出此異常。
例如,某個線程在 Collection 上進行疊代時,通常不允許另一個線性修改該 Collection。通常在這些情況下,疊代的結果是不确定的。如果檢測到這種行為,一些疊代器實作(包括 JRE 提供的所有通用 collection 實作)可能選擇抛出此異常。執行該操作的疊代器稱為快速失敗 疊代器,因為疊代器很快就完全失敗,而不會冒着在将來某個時間任意發生不确定行為的風險。
注意:此異常不會始終指出對象已經由不同 線程并發修改。如果單線程發出違反對象協定的方法調用序列,則該對象可能抛出此異常。例如,如果線程使用快速失敗疊代器在 collection 上疊代時直接修改該 collection,則疊代器将抛出此異常。
注意:疊代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現不同步并發修改做出任何硬性保證。快速失敗操作會盡最大努力抛出
ConcurrentModificationException
。是以,為提高此類操作的正确性而編寫一個依賴于此異常的程式是錯誤的做法,正确做法是:
ConcurrentModificationException
應該僅用于檢測 bug。
Java中的For each實際上使用的是iterator進行處理的。而iterator是不允許集合在iterator使用期間删除的。是以導緻了iterator抛出了
ConcurrentModificationException
。
正确的方式(使用Iterator)
public static void listIterator3(){
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(2);
list.add(3);
list.add(4);
Iterator<Integer> it = list.iterator();
while (it.hasNext()){
Integer value = it.next();
if (2 == value) {
it.remove();
}
System.out.println(value);
}
System.out.println("list=" + list.toString());
}
複制
結果:
1
2
2
3
4
list=[1, 3, 4]
複制
這種方式可以正常的循環及删除。但要注意的是,使用iterator的remove方法,如果用list的remove方法同樣會報上面提到的ConcurrentModificationException錯誤。
二、Map周遊過程中删除元素
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("1", "test1");
map.put("2", "test2");
map.put("3", "test3");
map.put("4", "test4");
//完整周遊Map
for (Entry<String, String> entry : map.entrySet()) {
System.out.printf("key: %s value:%s\r\n", entry.getKey(), entry.getValue());
}
//删除元素
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while(it.hasNext()){
Map.Entry<String, String> entry= it.next();
String key= entry.getKey();
int k = Integer.parseInt(key);
if(k%2==1){
System.out.printf("delete key:%s value:%s\r\n", key, entry.getValue());
it.remove();
}
}
//完整周遊Map
for (Entry<String, String> entry : map.entrySet()) {
System.out.printf("key: %s value:%s\r\n", entry.getKey(), entry.getValue());
}
}
複制
結果:
key: 1 value:test1
key: 2 value:test2
key: 3 value:test3
key: 4 value:test4
delete key:1 value:test1
delete key:3 value:test3
key: 2 value:test2
key: 4 value:test4
複制
注意
但對于iterator的
remove()
方法,也有需要我們注意的地方:
每調用一次
iterator.next()
方法,隻能調用一次
remove()
方法。
調用
remove()
方法前,必須調用過一次
next()
方法。
JDK-API中對于remove()方法的描述:
void remove()
從疊代器指向的集合中移除疊代器傳回的最後一個元素(可選操作)。每次調用 next 隻能調用一次此方法。如果進行疊代時用調用此方法之外的其他方式修改了該疊代器所指向的集合,則疊代器的行為是不明确的。
抛出:
UnsupportedOperationException
- 如果疊代器不支援
remove
操作。
IllegalStateException
- 如果尚未調用
next
方法,或者在上一次調用
next
方法之後已經調用了
remove
方法。
總結
以上就是關于List與Map的周遊過程中删除元素的全部内容了,希望本文的内容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。