Iterator iterator Precautions

1, Iterator iterator

We usually often used to foreach, for keywords, in fact, use their internal principles are principles Iterator iterator. But when in use should be noted that, if in the process of adding elements traverse, delete elements and other changes List, structural List of HashMap and the like, will produce ConcurrentModificationException (concurrent modifications) exception.

2, analysis

We use a HashMap to analyze, look at the following piece of code:

HashMap<String, String> map = new HashMap<>();
map.put("1", "111");
map.put("2", "222");
map.put("3", "333);
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()) {
    Map.Entry<String, String> entry = iterator.next(); //这里会引发ConcurrentModificationException异常
    String key = entry.getKey();
    String value = entry.getValue();
    if(value.equals("111") {
        map.remove(key); 
        //map.put("444");
    }
}
复制代码

Trace from the lines of code into the exception is thrown, into the HashMap HashIterator class that implements the Iterator interface. The next () method will eventually execute the nextEntry () method. Look at the implementation nextEntry () method:

final Entry<K,V> nextEntry() {
	if (modCount != expectedModCount)
		throw new ConcurrentModificationException();
	HashMapEntry<K,V> e = next;
	if (e == null)
		throw new NoSuchElementException();

	if ((next = e.next) == null) {
		HashMapEntry[] t = table;
		while (index < t.length && (next = t[index++]) == null)
			;
	}
	current = e;
	return e;
}
复制代码

You can see the reason why thrown is modCount! = ExpectedModCount. modCount is a variable in the HashMap, when HashMap structural changes (such put into a new element, deleting a new element, etc.), this modCount record the number of times changed rather expectedModCount a variable HashIterator class object in HashIterator constructor assignment, as follows:

HashIterator() {
	expectedModCount = modCount;
	if (size > 0) { // advance to first entry
		HashMapEntry[] t = table;
		while (index < t.length && (next = t[index++]) == null)
			;
	}
}
复制代码

The above expectedModCount = modCount is the assignment statement. Back For the above example, when we deleted when traversing a HashMap element, i.e. map.remove (key); final execution removeEntryForKey (key) method, performed modCount ++ In this method, i.e. the value of modCount changed. As you proceed down to the HashIterator in nextEntry () method, because the value is not equal to modCount expectedModCount, then thrown ConcurrentModificationException exception.

3, why not throw an exception equal

We divergence that, if the if (modCount! = ExpectedModCount) sentence the judge sentences rid of it? Look at a situation, or use the above remove (key) as an example, if the key happens to be next to need a key to access it? Along nextEntry () look down:

final Entry<K,V> nextEntry() {
        ...省略
	HashMapEntry<K,V> e = next;
        ...省略
	if ((next = e.next) == null) {
		HashMapEntry[] t = table;
		while (index < t.length && (next = t[index++]) == null)
			;
	}
	current = e;
	return e;
}
复制代码

We will remove the abnormal situation. The next time that we delete the previous entry, this entry.next is empty, enter the if statement block, things to do if block is from the index began looking for an empty element. The value of the index is the position at which the entry has not been deleted. Speaking to listen to abstract, or plug-speak well:

For example, we removed the element number 3 in the traversal, this time index points to the next element, namely index = 3. As we continue to implement nextEntry, due hasMap changed, that table has changed, then the next visit to the element number is 5, which means that there is no element No. 4 is that we have access to, so this is problematic. So if HashMap Java provides the structure has changed, then throw concurrent modification exception.

4, how to add or remove elements while traversing?

Since the analysis can not be deleted HashMap when traversing above elements, then we have what kind of methods to remove or add it? Because we will certainly encounter problems at work. For deletion, we can see that there are ways a Iterator remove () of. And the HashIterator remove () method is as follows:

public void remove() {
	if (current == null)
		throw new IllegalStateException();
	if (modCount != expectedModCount)
		throw new ConcurrentModificationException();
	Object k = current.key;
	current = null;
	HashMap.this.removeEntryForKey(k);
	expectedModCount = modCount;
}
复制代码

Here you can see the current element is deleted by calling the HashMap removeEntryForKey, and synchronously expectedModCount modified to modCount, so the next execution nextEntry () will not be reported when abnormal concurrent modification method.

In the above case only a single thread will not be a problem, but if a multi-threaded, even with the remove () method, there will likely ConcurrentModificationException error. So in order to ensure on-site multi-thread safe, we need to HashMap to operate a locking operation, so you can prevent other site in the process of traversal to modify the structure of HashMap, resulting ConcurrentModificationException errors.

So if we want to add elements? It seems only implements Iterator remove () such a method, for other operations did not materialize for us, then we need to own up to achieve:

    LinkedList<Map.Entry<String, String>> tempList = new LinkedList<Map.Entry<String, String>>();
	tempList.addAll(map.entrySet());
	ListIterator<Map.Entry<String, String>> itor = tempList.listIterator();
	Map.Entry entry = null;

	while (itor.hasNext()) {
		 entry = (Map.Entry) itor.next();
		 Object key = entry.getKey();

		 if (key.toString().equals("3")) {
			map.put("33", "33");
		 }
	}
复制代码

We can use a LinkedList HashMap to load the entrySet, and then modify or add elements when traversing the map, since the LinkedList and HashMap of the Iterator Iterator objects are different, so do not worry will lead to concurrent modification exception.

5, document reference:

www.cnblogs.com/Scott007/p/…

Guess you like

Origin juejin.im/post/5d7318b85188250a98581eda