Java 在Iterator中 remove & Concurr

2021-03-15  本文已影响0人  眼若繁星丶

前言

import java.util.*;

public class Solution {

    public static void main(String[] args) {
        List<String> arrayList = new ArrayList<String>();
        arrayList.add("a");
        arrayList.add("b");
        arrayList.add("c");
        arrayList.add("d");

        Iterator<String> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            String cur = iterator.next();
            if ("b".equals(cur)) {
                arrayList.remove(cur);
            } else {
                System.out.println(cur + " ");
            }
        }
        /*for (String s : arrayList) {
            if ("b".equals(s)) {
                arrayList.remove(s);
            } else {
                System.out.println(s + " ");
            }
        }*/
        System.out.println(arrayList);
    }
}

a
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayListItr.checkForComodification(ArrayList.java:937) at java.base/java.util.ArrayListItr.next(ArrayList.java:891)
at Solution.main(Solution.java:14)

import java.util.*;

public class Solution {

    public static void main(String[] args) {
        List<String> arrayList = new ArrayList<String>();
        arrayList.add("a");
        arrayList.add("b");
        arrayList.add("c");
        arrayList.add("d");

        Iterator<String> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            String cur = iterator.next();
            if ("c".equals(cur)) {
                arrayList.remove(cur);
            } else {
                System.out.println(cur + " ");
            }
        }
        /*for (String s : arrayList) {
            if ("c".equals(s)) {
                arrayList.remove(s);
            } else {
                System.out.println(s + " ");
            }
        }*/
        System.out.println(arrayList);
    }
}

a
b
[a, b, d]

分析

public Iterator<E> iterator() {
    return new Itr();
}
private class Itr implements Iterator<E> {
    /**
     * Index of element to be returned by subsequent call to next.
     */
    int cursor = 0;

    /**
     * Index of element returned by most recent call to next or
     * previous.  Reset to -1 if this element is deleted by a call
     * to remove.
     */
    int lastRet = -1;

    /**
     * The modCount value that the iterator believes that the backing
     * List should have.  If this expectation is violated, the iterator
     * has detected concurrent modification.
     */
    int expectedModCount = modCount;

    public boolean hasNext() {
        return cursor != size();
    }

    public E next() {
        checkForComodification();
        try {
            int i = cursor;
            E next = get(i);
            lastRet = i;
            cursor = i + 1;
            return next;
        } catch (IndexOutOfBoundsException e) {
            checkForComodification();
            throw new NoSuchElementException();
        }
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            AbstractList.this.remove(lastRet);
            if (lastRet < cursor)
                cursor--;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException e) {
            throw new ConcurrentModificationException();
        }
    }

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

The number of times this list has been structurally modified. Structural modifications are those that change the size of the list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.
This field is used by the iterator and list iterator implementation returned by the iterator and listIterator methods. If the value of this field changes unexpectedly, the iterator (or list iterator) will throw a ConcurrentModificationException in response to the next, remove, previous, set or add operations. This provides fail-fast behavior, rather than non-deterministic behavior in the face of concurrent modification during iteration.
Use of this field by subclasses is optional. If a subclass wishes to provide fail-fast iterators (and list iterators), then it merely has to increment this field in its add(int, E) and remove(int) methods (and any other methods that it overrides that result in structural modifications to the list). A single call to add(int, E) or remove(int) must add no more than one to this field, or the iterators (and list iterators) will throw bogus ConcurrentModificationExceptions. If an implementation does not wish to provide fail-fast iterators, this field may be ignored.

protected transient int modCount = 0;
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();
}

所以在 add remove 的过程中 modCount会自增自减。如果用集合的 remove则 List 的modCount减少一,而 Iterator 的 expectedModCount不变,就会抛出异常。

while + iterator 的组合是需要先判空 hasNext(),然后再next(),最后才 remove(),否则会报错,可以自行实验,调换 next 和 remove。

因为要先 next,将游标越过当前的元素,然后再决定要怎么操作当前的(游标前面的)这个元素,即游标是插在 当前元素 和 下一个元素的中间(可以这么理解)。

删除倒数第二个元素的时候,cursor指向最后一个元素,而此时删掉了倒数第二个元素后,cursor和size()正好相等了,所以hasNext()返回false,遍历结束,成功的删除了倒数第二个元素。

建议用法

import java.util.*;

public class Solution {

    public static void main(String[] args) {
        List<String> arrayList = new ArrayList<String>();
        arrayList.add("a");
        arrayList.add("b");
        arrayList.add("c");
        arrayList.add("d");

        Iterator<String> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            String cur = iterator.next();
            if ("a".equals(cur)) {
                iterator.remove();
            } else {
                System.out.println(cur + " ");
            }
        }
        System.out.println(arrayList);
    }
}

b
c
d
[b, c, d]

上一篇 下一篇

猜你喜欢

热点阅读