Skip to content

Instantly share code, notes, and snippets.

@pyq
Created May 7, 2015 03:13
Show Gist options
  • Save pyq/346eccb02631781d29f0 to your computer and use it in GitHub Desktop.
Save pyq/346eccb02631781d29f0 to your computer and use it in GitHub Desktop.
Why do you get a ConcurrentModificationException when using an iterator?
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