为什么这是合法的:
for(int i=0; i < arr.size(); i++) {
arr.remove(i);
}
Run Code Online (Sandbox Code Playgroud)
但是使用迭代器或a的语法糖会导致ConcurrentModificationException:
for(String myString : arr) {
arr.remove(myString);
}
Run Code Online (Sandbox Code Playgroud)
iterator.remove();我问为什么不同的行为,而不是如何避免conc mod异常.谢谢.我们来看看eg的ArrayLists迭代器是如何实现的:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
public E next() {
checkForComodification();
int i = cursor;
if (i >= size) throw new NoSuchElementException();
// ...
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
// ...
ArrayList.this.remove(lastRet);
// ...
cursor = lastRet;
lastRet = -1;
}
Run Code Online (Sandbox Code Playgroud)
让我们看一个例子:
List list = new ArrayList(Arrays.asList(1, 2, 3, 4));
Iterator it = list.iterator();
Integer item = it.next();
Run Code Online (Sandbox Code Playgroud)
我们删除第一个元素
list.remove(0);
Run Code Online (Sandbox Code Playgroud)
如果我们现在想调用it.remove(),迭代器将删除数字 2,因为这就是 fieldlastRet现在所指向的。
if (item == 1) {
it.remove(); // list contains 3, 4
}
Run Code Online (Sandbox Code Playgroud)
这是不正确的行为!迭代器的契约规定remove()删除返回的最后一个元素next(),但在存在并发修改的情况下无法保持其契约。因此,为了安全起见,它选择抛出异常。
对于其他收藏品来说,情况可能更加复杂。如果您修改 a HashMap,它可能会根据需要增大或缩小。那时,元素将落入不同的存储桶,并且在重新散列之前保留指向存储桶的指针的迭代器将完全丢失。
请注意,它iterator.remove()本身不会引发异常,因为它能够更新自身和集合的内部状态。然而,调用remove()同一实例集合的两个迭代器会抛出异常,因为这会使其中一个迭代器处于不一致的状态。
| 归档时间: |
|
| 查看次数: |
119 次 |
| 最近记录: |