1.foreach
执行下面这段代码的时候会抛出异常
1
2
3
4
5
6
7
8
9
10
11
12public 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两个值,初始化的时候默认相等。
1
2
3
4
5
6
7
8
9
10public 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的值改变了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public 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的值是不是相等,不相等则抛出异常。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public 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。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public 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,所以不会抛出异常。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17private 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总结内容请搜索靠谱客的其他文章。
发表评论 取消回复