2017-03-03 58 views
0

我使用Iteratot迭代ArrayList的元素。迭代我在最後將一個元素添加到ArrayList中。但出現錯誤:ConcurrentModificationException。如果我在迭代結束時在ArrayList中添加元素,則拋出ConcurrentModificationException

如果我改變ArrayList的設置,並試圖迭代過程中在最後添加在集合中的元素沒有錯誤拋出

Test.java

class Test { 
    public static void main() { 
    ArrayList<Integer> al = new ArrayList<Integer>(); 
    al.add(20); 
    al.add(30); 
    al.add(40); 

    Iterator<Integer> it = marks.iterator(); 
    while (it.hasNext()) { 
     int value = it.next(); 
     if (value == 40) al.add(50); 
    } 
    } 
} 

Test2.java

class Test2 { 
    public static void main() { 
    Set<Integer> marks = new HashSet<>(); 
    marks.add(20); 
    marks.add(30); 
    marks.add(40); 

    Iterator<Integer> it = marks.iterator(); 
    while (it.hasNext()) { 
     int value = it.next(); 
     if (value == 40) marks.add(50); 
    } 
    } 
} 
+2

您發佈的代碼實際上並未進行編譯。請提供一個[mcve] ...雖然它不需要大量工作來改變它,但最好是一次完成,而不是每個讀者都必須這樣做。 –

+2

噢,和'ArrayList'一樣''HashSet'也有同樣的錯誤... –

+1

由於您正在使用的'HashSet'的具體實現,沒有通過'HashSet'得到它是一種僥倖。 –

回答

4

有可能是一個更好的解決方案,但這個工作也是如此。在循環結束後,使用第二個列表,然後將其添加到原始列表中。

主要

import java.util.ArrayList; 
import java.util.Iterator; 
import java.util.List; 

public class Main { 

    public static void main(String[] args) { 
     List<Integer> al = new ArrayList<Integer>(); 
     List<Integer> toAdd = new ArrayList<Integer>(); 
     int stepSize = 10; 

     al.add(20); 
     al.add(30); 
     al.add(40); 

     Iterator<Integer> it = al.iterator(); 
     while (it.hasNext()) { 
      int value = it.next(); 
      if (value == al.get(al.size() - 1)){ 
       toAdd.add(value + stepSize); 
      } 
     } 

     // Add all elements 
     al.addAll(toAdd); 

     // Print 
     al.forEach(System.out::println); 
    } 
} 

如果你只希望基於上次值一個元素追加,因爲在你的榜樣,你也可以等到循環結束(如果你還需要它),並嘗試添加這樣的:

al.add(al.get(al.size() - 1) + stepSize); 

輸出

20 
30 
40 
50 
0

是的,這是普通列表的預期。

您可以使用CopyOnWriteArrayList進行List上的併發活動。

例如,click here

+0

我認爲這個隱含的問題是爲什麼它*不會出現在HashSet中。 –

+0

在HashSet中也可能會出現同樣的問題。 http://stackoverflow.com/questions/12562548/concurrentmodificationexception-and-hashset-iterator – sitakant

1

你不會得到ConcurrentModificationExceptionHashSet。這種僥倖的原因是,你碰巧在循環的迭代上添加了元素。

這遠未保證發生,因爲HashSet沒有訂單保證。嘗試從列表中添加或刪除更多元素,並且您會發現最終能夠獲得ConcurrentModificationException,因爲40不會是列表中的最後一個元素。

重現這個最簡單的方法是,只是一個單一元件的作用(自那時以來,HashSet的順序是已知的):

HashSet<Integer> hashSet = new HashSet<>(); 
hashSet.add(1); 
for (int i : hashSet) { 
    hashSet.add(2); 
} 

這不會拋出ConcurrentModificationException

ArrayList<Integer> list = new ArrayList<>(); 
list.add(1); 
for (int i : list) { 
    list.add(2); 
} 

拋出ConcurrentModificationException


至於爲何在最後一次迭代增加了一個HashSet,當你沒有得到異常的原因, 看看爲返回的迭代器的源代碼通過HashSet.iterator()

abstract class HashIterator { 
    // ... 

    public final boolean hasNext() { 
     return next != null; 
    } 

    // ... 
} 

所以,hasNext()值是根據next預先計算的;此設定得較低向下代碼中的一個位:

final Node<K,V> nextNode() { 
     Node<K,V>[] t; 
     Node<K,V> e = next; 
     if (modCount != expectedModCount) 
      throw new ConcurrentModificationException(); 
     if (e == null) 
      throw new NoSuchElementException(); 
     if ((next = (current = e).next) == null && (t = table) != null) { 
      do {} while (index < t.length && (next = t[index++]) == null); 
              //^Here 
     } 
     return e; 
    } 

所以,當確定迭代的前一個元素被確定的hasNext值。

由於您的代碼是:

Iterator it = marks.iterator(); 
while (it.hasNext()) { 
    int value = it.next(); 
    if (value == 40) 
    marks.add(50); 
} 

hasNext()在其中添加元素的循環迭代之後被調用;但在調用it.next()之前next被設置爲空 - 在調用add之前 - 因此hasNext()將返回false,並且該循環退出而沒有ConcurrentModificationException


在另一方面,iterator of ArrayList使用底層列表的大小來確定的hasNext()返回值:

public boolean hasNext() { 
     return cursor != size; 
      //^current position of the iterator 
      //   ^current size of the list 
    } 

所以這個值是「活的」關於增加(或減少)底層列表的大小。因此,hasNext()將在添加該值後返回true;所以調用next()。但是,第一件事情是next()確實是檢查商品化:

public E next() { 
     checkForComodification(); 
     // ... 

,因此是檢測到的變化,並且ConcurrentModificationException被拋出。

請注意,您不會得到ConcurrentModificationExceptionArrayList如果你修改了它的最後一次迭代,如果你要添加和刪除元素(或者,更確切地說,添加和刪除元素的數量相等,以便列表的大小相同)。

相關問題