概述
1.foreach
执行下面这段代码的时候会抛出异常
public void testForeach() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
//foreach
for (Integer integer : list) {
if (integer == 6) {
list.remove(integer);
}
}
}
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
然后跟踪到错误源,发现ArrayList中的iterator中有expectedModCount和modCount两个值,初始化的时候默认相等。
public Iterator<E> iterator() {
return new Itr();
}
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
int expectedModCount = modCount;
...
}
执行到list.remove(integer)的时候,remove方法进入到fastRemove方法,然后modCount的值改变了。
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
继续循环遍历的时候会用到iterator中的next方法,其中checkForComodification()会检查expectedModCount和modCount的值是不是相等,不相等则抛出异常。
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();
}
2.iterator
执行下面这段代码,输出结果为9。
public void testIterator() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
//Iterator
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Integer integer = (Integer) iterator.next();
if (integer == 6) {
iterator.remove();
}
}
System.out.println(list.size());
}
查看源码,当使用iterator.remove()的时候,删除完后会执行expectedModCount = modCount,所以不会抛出异常。
private class Itr implements Iterator<E> {
...
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();
}
...
}
总结
1.使用foreach循环遍历,其实是内部调用迭代器实现,迭代器中会有expectedModCount、modCount两个值,如果两个值不相等,在遍历的时候会抛异常。
2.集合和iterator的remove方法是有区别的,iterator的remove删除后会使expectedModCount = modCount,而集合的remove没有,所以在中foreach中使用集合的remove时,再次遍历的时候会抛异常。
3.for循环不涉及iterator,故可以直接删除集合中的元素。
最后
以上就是完美啤酒为你收集整理的foreach与iterator总结的全部内容,希望文章能够帮你解决foreach与iterator总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复