Created
May 7, 2015 03:13
-
-
Save pyq/346eccb02631781d29f0 to your computer and use it in GitHub Desktop.
Why do you get a ConcurrentModificationException when using an iterator?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.Iterator; | |
/** | |
* Created by pyq on 5/6/15. | |
*/ | |
/* | |
1. how does hasNext() work | |
public boolean hasNext() { | |
return cursor != size; | |
} | |
size: the number of elements it contains | |
cursor: index of next element to return | |
2. how does next() work | |
public E next() { | |
checkForComodification(); | |
.. | |
returns the next element in the iteration | |
} | |
3. how does checkForComodification() work | |
final void checkForComodification() { | |
if (modCount != expectedModCount) | |
throw new ConcurrentModificationException(); | |
} | |
modCount: The number of times this list has been structurally modified. | |
4. iterator.remove(); // increase modCount and also update expectedModCount, make it equal to modCount. | |
5. collection.remove(value); // only increase modCount | |
*/ | |
public class IteratorRemove { | |
public static void removeWithTwo() { | |
Collection<String> collection = new ArrayList<String>(2); | |
collection.add("one"); | |
collection.add("two"); | |
System.out.printf("%d%n", collection.size()); // 2 | |
for (String value : collection) { | |
System.out.printf("%s%n", collection.remove(value)); // true | |
} | |
System.out.printf("%d%n", collection.size()); // 1 | |
} | |
/* | |
this for each loop just like following code | |
for (Iterator<String> iterator = collection.iterator(); iterator.hasNext();) { | |
String value = iterator.next(); | |
System.out.printf("%s%n", collection.remove(value)); | |
} | |
after removed index 0 element(cursor 0), then increased the cursor by 1, now cursor is 1. | |
(at the same time, size will decreased by 1, size is from 2 to 1) | |
Because cursor == size. hasNext return false, (jump out of loop) | |
We don't invoke next() after we removed the element "one", so we will not get ConcurrentModificationException | |
and the collection.size() will just return size = 1. | |
*/ | |
public static void removeWithThree() { | |
Collection<String> collection = new ArrayList<String>(2); | |
collection.add("one"); | |
collection.add("two"); | |
collection.add("three"); | |
System.out.printf("%d%n", collection.size()); // 3 | |
for (String value : collection) { | |
System.out.printf("%s%n", collection.remove(value)); // true then throws ConcurrentModificationException | |
} | |
System.out.printf("%d%n", collection.size()); | |
} | |
// removeWithThree is just like removeWithThreeII | |
/* with three element after we removed "one", cursor is 1, size is 2 (3 - 1), the hasNext will return true, (modCount++) | |
now we jump to the next iteration of the loop(trying to remove "two"), | |
but when invoke next(). we will throw ConcurrentModificationException (since modCount != expectedModCount) modeCount now is equal to expectedModCount + 1 | |
*/ | |
public static void removeWithThreeII() { | |
Collection<String> collection = new ArrayList<String>(2); | |
collection.add("one"); | |
collection.add("two"); | |
collection.add("three"); | |
System.out.printf("%d%n", collection.size()); // 3 | |
for (Iterator<String> itr = collection.iterator(); itr.hasNext();) { | |
String value = itr.next(); | |
System.out.printf("%s%n", collection.remove(value)); // true then throws ConcurrentModificationException | |
} | |
System.out.printf("%d%n", collection.size()); | |
} | |
//Iterator.remove is the only safe way to modify a collection during iteration | |
// when execute iterator.remove(); we will have modCount++ and expectedModCount = modCount. These two variables are always the same. | |
public static void correctRemoveWithThree() { | |
Collection<String> collection = new ArrayList<String>(2); | |
collection.add("one"); | |
collection.add("two"); | |
collection.add("three"); | |
System.out.printf("%d%n", collection.size()); // 3 | |
Iterator<String> iterator = collection.iterator(); | |
while (iterator.hasNext()) { | |
iterator.next(); | |
iterator.remove(); | |
} | |
System.out.printf("%d%n", collection.size()); | |
} | |
public static void main(String[] args) { | |
//removeWithTwo(); | |
//removeWithThree(); | |
//removeWithThreeII(); | |
correctRemoveWithThree(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment