為什麼在foreach迴圈中進行元素remove/add操作,會拋ConcurrentModificationException 異常?
阿新 • • 發佈:2018-12-08
執行以下程式碼:
@Test public void test() { List<String> list = new ArrayList<>(); list.add("A"); list.add("B"); for (String temp : list) { // 當為A時執行正常,改成B時異常ConcurrentModificationException if ("B".equals(temp)) { list.remove(temp); } } }
執行結果:
編譯後的Class檔案:
@Test public void test() { List<String> list = new ArrayList(); list.add("A"); list.add("B"); Iterator var2 = list.iterator(); while(var2.hasNext()) { String temp = (String)var2.next(); if("B".equals(temp)) { list.remove(temp); } } }
可以發現原始碼與編譯後的位元組碼不一樣,原始碼中的“for (String temp : list) {”在真實的位元組碼中是
“Iterator var2 = list.iterator();
while(var2.hasNext()) {
String temp = (String)var2.next();”
對應的原始碼:
list.iterator()對應方法的原始碼:
new Itr()建立物件時,會將modCount值賦值給expectedModCount,而modCount該欄位在ArrayList中標識當前物件的修改次數(包括remove和add方法)
add()
remove()
進入while迴圈時,執行var2.hasNext()方法:
cursor初始化的時候是0,每執行一次next()方法,值自動加1,cursor == size時會跳出迴圈
當執行next()方法時,首先會執行checkForComodification()方法
檢視程式碼,可以看出當modCount != expectedModCount時,就會丟擲ConcurrentModificationException
expectedModCount的值是在建立Itr物件賦值的,而遍歷集合的時候,再執行一次remove或add就會導致modCount的值修改,而此時expectedModCount的值未變化,就會報異常ConcurrentModificationException。
如果非要在迴圈裡面remove、add 元素,請使用 Iterator 方式,如果併發操作,需要對 Iterator 物件加鎖。
ListIterator iterator = list.listIterator();
while (iterator.hasNext()) {
String item = (String) iterator.next();
if("B".equals(item)){
iterator.add("C");
// iterator.remove();
}
System.out.println("改變後的資料:" + list.toString());
}