Why Alibaba Java Developer's Handbook mandatory remove and add operations not carried out in the elements in the foreach loop?

In reading "Ali Baba Java Development Manual", were found on a statute element in the foreach loop in the remove / add operations, as follows:

Alibaba Java Development Manual

Error demo

We start by writing a code in IDEA remove operation in the foreach loop:

import java.util.ArrayList;
import java.util.List;

public class ForEachTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("wupx");
        list.add("love");
        list.add("huxy");
        for (String temp : list) {
            if ("love".equals(temp)) {
                list.remove(temp);
            }
        }
        System.out.println(list);
    }
}

Run the code, compile properly executed successfully! Output [wupx, huxy].

Then we "love" replaced by "wupx" or "huxy" run again, the results are as follows:

Nani, actually being given, why the first run without being given it? Let's discuss it!

Tracing the source

In order to study why there is such a situation, we can abnormal stack information, to track errors, which related to the portion of the source code as follows:

private class Itr implements Iterator<E> {
    int cursor;       // 下一个要返回的元素的索引
    int lastRet = -1; // 返回的最后一个元素的索引(如果没有返回-1)
    int expectedModCount = modCount;

    public boolean hasNext() {
        return cursor != size;
    }
    
    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void forEachRemaining(Consumer<? super E> consumer) {
        Objects.requireNonNull(consumer);
        final int size = ArrayList.this.size;
        int i = cursor;
        if (i >= size) {
            return;
        }
        final Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length) {
            throw new ConcurrentModificationException();
        }
        while (i != size && modCount == expectedModCount) {
            consumer.accept((E) elementData[i++]);
        }
        cursor = i;
        lastRet = i - 1;
        checkForComodification();
    }
    
    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

As can be seen from the code, actually maintains an initial value 0 is set when cursor cursor traversing, scanning is performed from start to finish, when the cursor == size, exit traversal. As shown below, after performing remove this element, all the elements forward copies, size = size-1 that is 2, then the cursor is also equal to 2. Performed
when the hasNext (), the result is false, the loop exits, and no chance to perform a next () of the first line of code
checkForComodification (), and the method used to determine expectedModCount modCount are equal,
if not equal, it is thrown ConcurrentModificationException exception.

cursor with the size of the collection

The reason will be reported ConcurrentModificationException exception is triggered because of Java's fail-fast mechanism, which is a collection of the more common error detection mechanism, usually appears during the walk through the collection elements. For the life of chestnuts:

For example, physical education courses, will be followed by a few newspaper before class, if during the reported number, someone suddenly add to the mix, but also to re-count off, count off again, students have slipped out, but also to re-report the number, which is fail -fast mechanism, which is set (classmates) traversing the error detection mechanism operated when modifying traversal unexpected occurs halfway through unchecked exceptions out feedback. This mechanism often occurs in a multithreaded environment, the current thread maintains a count comparator (expectedModCount), the number of records that have been modified. Before entering traversal, will modify the number of real-time
modCount assigned to expectedModCount, if the two data are not equal, an exception is thrown. All collections in java.util are fail-fast.

The only way

Deleted or added since the time of remove / add elements operating there will be problems in the foreach loop, then we can use the manual for the recommended Iterator traversal mechanism, as follows:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ForEachTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("wupx");
        list.add("love");
        list.add("huxy");

        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            if (iterator.next().equals("wupx")) {
                iterator.remove();
            }
        }
        System.out.println(list);
    }
}

If multithreading is also required at the time of locking Iterator traversal, instead of or concurrent CopyOnWriteArrayList the ArrayList container, the inner container will Iterator for locking operation.

to sum up

This paper not to carry out elements in the foreach loop in for the "Ali Baba Java Development Manual" mandatory remove / add operations starting from the source level to explain why, but also with life chestnuts to introduce fail-fast mechanism in Java, So remove conducting elements / add operations when to use Iterator to traverse delete or add.

reference

"Java Development Manual" Mountain Edition

"A highly efficient code: Java Development Manual"

Guess you like

Origin www.cnblogs.com/wupeixuan/p/11974270.html