When I ran the following code
Caught expected ConcurrentModificationException
is printed which is expected but strange thing is on second iteration no exception is being caught and
Failed to catch expected ConcurrentModificationException
is printed. I am really not sure why for second time it is not caught.
public class TestLHS {
public static void main(String[] args) {
LinkedHashSet<Integer> lhSet = new LinkedHashSet<Integer>();
Integer one = new Integer(1);
Integer two = new Integer(2);
Integer three = new Integer(3);
Integer four = new Integer(4);
Integer cinco = new Integer(5);
// Add the three objects to the LinkedHashSet.
// By its nature, the LinkedHashSet will iterate in
// order of insertion.
lhSet.add(one);
lhSet.add(two);
lhSet.add(three);
// 1. Iterate over set. try to insert while processing the
// second item. This should throw a ConcurrentModificationEx
try {
for (Iterator<Integer> it = lhSet.iterator(); it.hasNext();) {
Integer num = (Integer) it.next();
if (num == two) {
lhSet.add(four);
}
System.out.println(num);
}
} catch (ConcurrentModificationException ex) {
System.out.println("Caught expected ConcurrentModificationException");
}
// 2. Iterate again, this time inserting on the (old) 'last'
// element. This too should throw a ConcurrentModificationEx.
// But it doesn't.
try {
for (Iterator<Integer> it = lhSet.iterator(); it.hasNext();) {
Integer num = (Integer) it.next();
if (num == four) {
lhSet.add(cinco);
}
System.out.println(num);
}
System.out.println("Failed to catch expected ConcurrentModificationException");
} catch (ConcurrentModificationException ex) {
System.out.println("Caught expected ConcurrentModificationException");
}
}
}
Can someone explain this behavior?
Let's look at the documentation:
if the set is modified at any time after the iterator is created, in any way except through the iterator's own
remove
method, the iterator will throw aConcurrentModificationException
.
Notice that it's not clear exactly which iterator method will throw the exception. Let's check the source:
public final boolean hasNext() {
return next != null;
}
// called by LinkedKeyIterator.next()
final LinkedHashMap.Entry<K,V> nextNode() {
LinkedHashMap.Entry<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
current = e;
next = e.after;
return e;
}
As you can see, the exception is thrown by the next()
method, not by hasNext()
. Since four
is the last element in the set, next
is already null, so the next call to hasNext()
returns false and next()
isn't called again. Therefore, the concurrent modification is not observed and no exception is thrown.
See also Why isn't this code causing a ConcurrentModificationException?