Java 中list(ArrayList)的foreach遍歷方式呼叫list的remove刪除元素,不丟擲ConcurrentModificationException
關於list刪除元素的當時有很多,具體可以參考下面這個部落格。
https://blog.csdn.net/claram/article/details/53410175
裡面提到了list的foreach遍歷方式刪除元素,會丟擲ConcurrentModificationException。foreach是迭代器遍歷的一種簡寫。
但是,如果list中只有兩個元素,刪除第一個元素時,則不會丟擲ConcurrentModificationException異常。
首先看一下迭代器的hasNext()
和next()
方法原始碼。
public boolean hasNext() {
// 當前元素的位置不等於list的size代表還有元素沒有遍歷
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
//檢查是否有迭代器之外的modify
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this .elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
final void checkForComodification() {
//expectedModCount 是迭代器自己維護的變數
//modCount 是list中元素修改的數量
//如果呼叫迭代器的方法對list操作,二者是相等的。例如下面的remove方法
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
//保證expectedModCount和modCount相等
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
在看一下ArrayList的remove方法。
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
//移除元素,modcount++
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
假設ArrayList只有兩個元素,刪除第一個元素的程式碼如下:
public static void main(String []args) {
List<String> list = new ArrayList<>();
list.add("ddd");
list.add("aaa");
for (String string : list) {
if (string.equals("aaa")) {
list.remove(string);
}
System.out.println(string);
}
}
上面程式碼並沒有丟擲任何異常,關鍵在於迭代器遍歷第一個元素後,此時cursor=1,modCount=expectedModCount=2,size=2;
刪除第一個元素後,cursor=1,modCount=3,expectedModCount=2,size=1;
繼續執行迭代器的hasNext()時,發現cursor==size==1,迭代器認為已經遍歷結束。並沒有繼續執行next函式,還沒有來得及執行checkForComodification()
迴圈已經結束。
總結
在這種特殊情況下,雖然此時並沒有丟擲異常,但是也沒有按照我們的預想,將兩個元素全部遍歷完,只遍歷了一個元素就結束了,在刪除元素時,還應當使用迭代器更加安全。
相關推薦
Java 中list(ArrayList)的foreach遍歷方式呼叫list的remove刪除元素,不丟擲ConcurrentModificationException
關於list刪除元素的當時有很多,具體可以參考下面這個部落格。 https://blog.csdn.net/claram/article/details/53410175 裡面提到了list的foreach遍歷方式刪除元素,會丟擲ConcurrentMo
Java中List集合的遍歷(三種遍歷方式效率的比較)
public static void main(String args[]){ compare(); } public static void compare() { List<String> list = new ArrayList
Java中List集合的遍歷
java list 集合 遍歷 一、對List的遍歷有三種方式 List<String> list = new ArrayList<String>(); list.add("testone"); list.add(
Java中list如何利用遍歷進行刪除操作
Java三種遍歷如何進行list的便利刪除:1、for迴圈:常見初五寫法:(由於下標問題達不到想要效果)for(int i=0;i<list.size();i++){ if(list.get(i).equals("del")) list.remo
java中Map,兩種遍歷方式
package cn.mdln.study3; import java.util.Map; import java.util.Set; import java.util.Iterator; import java.util.HashMap; /** * Map,兩種遍歷方
Android中List循環遍歷性能對照
最快 next() num trac () ren length iter pan 在android開發中僅僅要是列表式風格界面我們差點兒都須要用到List來存放數據,在數量非常少的List的話差點兒不論什麽一種循環遍歷方式總體性能都無區別。可是當我們遇
java中Set集合的遍歷方法
基本數據類型 對象 叠代器 比較 for hashset 循環 sta ins S兒童集合的遍歷: 第一種:for增強循環 Set<String> set = new HashSet<String>(); for (String str : set
總結下List和Map遍歷方式(日常總結)
一.Map public static void main(String[] args) { Map<Integer, Integer> map = new HashMap<>(); map.put(1, 2);
java集合的三種遍歷方式以及各自優缺點分析
1、Iterator介面 Iterator是Java集合框架的成員,主要用於遍歷(即迭代訪問)Collection集合中的元素,也稱為迭代器。 提供的三種方法: boolean hasNext():返回集合裡的下一個元素。 Object next():
Java中使用size()方法遍歷PriorityQueue出現元素不全的問題
在使用PriorityQueue類時 使用 for(int i=0; i<priorityqueue.size(); i++) 與 for(int i : priorityqueue) 遍歷PriorityQueue時 有時會出現PriorityQueue未能正常排序
java中Set集合的遍歷及實現類比較分析
java中Set集合是一個不包含重複元素的Collection,首先我們先看看遍歷方法 package com.sort; import java.util.HashSet; import java.util.Iterator; import java.util.Set;
vue.js中的兩種遍歷方式(以及substring,split,getJsonLength)
第一種: $.each($('.active'), function(index, item){ attrTxt+= (' ' + $(item).text()); attrid
Vue中v-for遍歷多層巢狀資料,不能重新渲染的問題
問題 { "properties": [ [ { "name": "property_name", "example": "travel_time", "value": "" }, { "name":
二叉樹的建立(先序)先序中序後序遍歷(遞迴演算法),求葉子結點個數,求樹的高度,樹中結點的個數,值為data的結點所在的層數
#include<iostream> #include<cstdio> #include<malloc.h> #define OVERFLOW -2 typedef struct BiTNode{ char data;
Java中List集合遍歷的三種方式
asn tex iter for nbsp next next() ray string 首先創建一個List集合: List<String> list = new ArrayList<String>();list.add("name"); list
Java(8)中List的遍歷方式
system pack map 新建 lam entry lambda googl list() ============Java8之前的方式==========Map<String, Integer> items = new HashMap<>()
Java中集合類set、List和map的遍歷方式
Java中集合類的遍歷方式 Java中集合分為set、List和map。 1.set集合 set集合常用的有兩種遍歷方式: Set<String> set = new HashSet<String>(); 第一種利用for迴圈: for(S
Java中 List(ArrayList) 的五種遍歷例子
package Strings; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Lists { public static vo
Java中使用foreach遍歷list的盲點,
我們通常在專案中會用到ArrayList ,喜歡使用jdk1.5以後的foreach進行對list集合遍歷,但是以下的操作會遇到小坑請看程式碼:public class TestListUtils {
java中List、Set、Map集合遍歷的幾種方式小結和比較
一、集合類的通用遍歷方式, 用迭代器迭代:1.迭代遍歷whileIterator it = list.iterator();while(it.hasNext()){Object obj = it.next();System.out.println(it.next());}2.