0

I am confused by one specific point regarding synchronization feature of LinkedHashMap. Here are the related Javadoc where I am confused. My confusion point is, why remove method is special here, which is mentioned by -- "except through the iterator's own remove method"?

http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html

The iterators returned by the iterator method of the collections returned by all of this class's collection view methods are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

thanks in advance, Lin

Lin Ma
  • 9,739
  • 32
  • 105
  • 175

3 Answers3

4

Basically, you're not allowed to structurally modify a map while iterating over it, since doing so would invalidate the iterator.

Iterator.remove() is specifically exempt from this, to enable you to easily write code like this:

Iterator<E> it = coll.iterator();
while (it.hasNext()) {
  E val = it.next();
  if (some_condition) {
    it.remove();
  }
}
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Thanks NPE, sorry for the late reply. So since Iterator.remove just remove an element from the iterator itself, and it does not impact the original map itself, so it is safe? – Lin Ma Feb 12 '13 at 12:40
2

It isn't special, it's the normal way of removing some item from a collection when using an iterator. If an element is removed "outside" the iterator, the iterator view of the given collection becomes inconsistent as compared to the actual collection since the iterator has no way of knowing why or how the element was removed.

Iterators can be of different types. There are iterators which "operate" on a given state of the collection in which case modifying the collection outside the iterator makes no difference. This is common for immutable collections. The other type of iterator is a "fail-fast" one which throws up an exception as soon as it finds out that the iterator is now looking at an old state of the collection (i.e. the collection was modified from outside). As mentioned in the docs, LinkedHashMap uses a fail-fast iterator.

Sanjay T. Sharma
  • 22,857
  • 4
  • 59
  • 71
  • Thanks Sanjay, sorry for the late reply. So since Iterator.remove just remove an element from the iterator itself, and it does not impact the original map itself, so it is safe? – Lin Ma Feb 12 '13 at 12:41
  • 1
    @LinMa: No; an iterator can be thought of as a collection agnostic object used for iterating over the items and changing them. The iterator itself doesn't have any data; it's just a read/write view over the original data. – Sanjay T. Sharma Feb 12 '13 at 13:18
  • Thanks Sanjay, and why Iterator.remove() is specifically exempted from the Javadoc I referred? – Lin Ma Feb 14 '13 at 14:13
  • 1
    @LinMa: That's because `LinkedHashMap` and the other `Map` classes don't have an iterator method. The Javadoc here is talking about the iterator returned when you do something like `yourMap.entrySet().iterator()`. Read the sentence carefully "iterator method of the collections returned by all of this class's collection view methods". It says this class's view methods and not this class's iterator method. – Sanjay T. Sharma Feb 14 '13 at 17:06
  • Thanks Sanjay. I think for any kinds of iterator (no matter returned by class's iterator method, or class's collection view methods), if we call any method on the iterator while at the same time the underlying collection changed, the method call on the iterator will fail. My question is why remove method will not fail if the underlying collection changed? – Lin Ma Feb 15 '13 at 12:21
  • 1
    @Lin Ma: As already mentioned, the idea is keep the collection mutation in check. Let's say you are interating over the collection and suddenly some elements are removed without using the iterator. Fail fast iterator guarantees that you are notified via an exception when that happens. Now, let's say we want to iterate using an iterator *and* at the same time remove an element using the same iterator. How would we go about doing this? This is where the `remove` method comes into play. If you will look at the code of any collection class, you should be able to see the logic which does this. – Sanjay T. Sharma Feb 15 '13 at 13:31
1

It's not special, it acquires a sort of lock on the LinkedHashMap so that you are able to remove elements just through its remove method.

This because, as specified before:

A structural modification is any operation that adds or deletes one or more mappings or, in the case of access-ordered linked hash maps, affects iteration order.

This means that you have a pending iterator on the data structure, allowing any modification would generate problems with respect to deterministic behavior (since the iterator would become inconsistent, as the underlying structure changed). So the implementation just make any structural modification fail with an exception as soon as you invoke any method if you have an open iterator on it.

Jack
  • 131,802
  • 30
  • 241
  • 343
  • Thanks Jack, sorry for the late reply. So since Iterator.remove just remove an element from the iterator itself, and it does not impact the original map itself, so it is safe? – Lin Ma Feb 12 '13 at 12:42