5

How does Iterator throw ConcurrentModificationException when we are adding some object after current node or removing some object after current node. Does Iterator maintain a copy or reference to the underlying collection?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
banjara
  • 3,800
  • 3
  • 38
  • 61

5 Answers5

5

The iterator maintains a reference to the underlying collection. If you add or remove an element, the iterator might be left at an impossible index, or the collection might change "out from underneath" the iterator.

Therefore, instead of letting the iterator get corrupted without letting you know, most collections do the courtesy of throwing a ConcurrentModificationException when you try to modify the collection while iterating, so you don't wind up with unpredictably corrupted iterators.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
2

By contract, you are not allowed to modify the collection while iterating over it (except by using Iterator.remove() et al).

Instead of randomly failing when you do this, the collection is nice enough to keep track of how many times it's been modified, and throw ConcurrentModificationException when it detects concurrent modification.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
1

That ConcurrentModificationException is probably your friend and you ought to learn to live with it. However, just for completeness:

There are non-Oracle collections out there that don't throw ConcurrentModificationException. They're faster (because they don't spend time checking) and, obviously, more flexible, but they require greater care when using.

Oracle has four (at last count) "Concurrent" classes that don't throw it either in java.util.concurrent (ConcurrentHashMap, ConcurrentLinkedQueue, ConcurrentSkipListMap, and ConcurrentSkipListSet). They're marginally slower than their non-concurrent equivalents, but they're thread-safe and they dont block. They won't scramble your data no matter what you do, but they won't stop you from scrambling it.

RalphChapin
  • 3,108
  • 16
  • 18
1

For removing you can use iterator.remove(), as follows:

for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Object object = iterator.next();
    /* ... */
    if (condition) {
       iterator.remove();
    }

For adding you can replace simple Iterator for ListIterator, as follows

ListIterator<Object> iterator = list.listIterator();
iterator.add(new Object());
Moesio
  • 3,100
  • 1
  • 27
  • 36
0

Of course an iterator has a link to the underlying collection, this avoids the copy. If you look for example at the source code of ArrayList iterator (ListItr), you'll see it mostly has a link to the list and a cursor.

So, don't share an iterator between threads and don't modify a collection on which you're iterating.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758