当被foreach循环迭代时,列表中的任何项都不能被移除。但是,当我们通过迭代器迭代它时,可以通过迭代器的remove()方法将其移除。
我理解fail-fast和fail-safe的概念,也知道Iterator是java为我们提供删除选项的方式。但是我想知道java提供的Iterator的remove()方法的内部实现,它简化了这个操作。
import java.util.*;
public class RemoveCollection {
public static void main(String[] args) {
List<String> ls = new ArrayList<String>();
ls.add("apple");
ls.add("orange");
ls.add("kiwi");
Iterator it = ls.iterator();
while(it.hasNext()) {
it.next();
//works fine and the item is removed from list
it.remove();
}
ls.add("apple");
ls.add("orange");
ls.add("kiwi");
while(it.hasNext()) {
it.next();
//throws concurrentmodification exception
ls.remove();
}
}
}发布于 2018-07-28 18:18:31
您可以通过简单地查看ArrayList的源代码来了解这一点,该源代码随JDK提供:
ArrayList有这个字段(继承自AbstractList):
protected transient int modCount = 0;每次对列表执行操作时,它都会递增。例如,ArrayList.remove()具有以下指令:
modCount++;ArrayList的迭代器具有以下代码:
int expectedModCount = modCount;
public E next() {
checkForComodification();
[...]
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}因此,正如您所看到的,当它迭代时,它会检查列表的modCount是否未被修改。
它的remove()方法执行以下操作:
ArrayList.this.remove(lastRet);
[...];
expectedModCount = modCount;因此,它从列表中删除该元素,然后更新其expectedModCount,以便在调用checkForComodification()时使用迭代器完成的下一次操作不会失败。
要理解的关键是,方法iterator()返回一个对象,该对象可以访问列表的内部结构。不仅能够迭代它的元素,而且还可以检查该列表在使用迭代器完成的两次操作之间是否已被修改。
发布于 2018-07-28 18:25:36
List扩展了AbstractList。这个抽象类包含方法iterator(),它返回一个新的迭代器(第287行)。您可以看到source code
public Iterator<E> iterator() {
return new Itr();
}下面几行(在线330上)在线368上有定义并实现方法remove()的private class Itr implements Iterator<E>的定义:
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();
}
}https://stackoverflow.com/questions/51570266
复制相似问题