为什么Foreach循环中为什么不能使用 remove/add操作?
为什么Foreach循环中为什么不能 使用 remove/add操作
foreach
语法糖是 Iterator
实现的
使用 foreach 循环再用其自身的list
的remove
或者add
操作会导致抛出 并发修改异常,触发了Java集合检测机制 fail-fast
。 这是Iterator
的fail-fast
快速失效机制,为了避免在并发过程中导致的修改列表的而抛出的异常。
下面来看下发生这个问题的代码
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
for (String s : list) {
list.remove(s);
}
System.out.println(list);
结果:导致了并发修改异常 ConcurrentModificationException
,有个checkForComodification
方法抛出异常,下面会分析
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at top.stormling.javacoresample.module.collection.ArrayListTest.main(ArrayListTest.java:15)
我们先来看下解糖后的代码
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
Iterator<String> iterator = list.iterator();
do {
if (!iterator.hasNext())
break;
String next = (String) iterator.next();//这段代码抛出的checkForComodification 方法
if (next.equals("A"))
list.remove(next); //注意这段代码
} while (true);
System.out.println(list);
我们注重看下 list.remove(next)
这个源码,
private void fastRemove(Object[] es, int i) {
modCount++; //注意这段代码
final int newSize;
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}
ArrayList#remove
方法中使用fastRemove
这个方法,从这段代码可以得知使用集合自身修改的操作(如remove
、add
方法),会导致修改次数modCount
增加。
前面我们看到抛出的异常中有个checkForComodification
抛出,这个是 iterator.next()
这里抛出的,也就是意味着当集合中使用集合本身remove() 修改集合后,下一次的 iterator
迭代器进行next()
方法是抛出的异常。我们来看下这里面的源码
注意:这里抛出的异常是在ArrayList
中的内部类 Itr
(Iterator
的实例)
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];
}
可以看到这里现调用了checkForComodification
方法,这个方法在 Itr
中
final void checkForComodification() {
if (ArrayList.this.modCount != this.expectedModCount) { //这段代码
throw new ConcurrentModificationException();
}
}
看到这里就会明白,如果我们使用集合本身去执行remove/add操作,或导致 modeCount
和 expectedModCount
不相等
modCount
:是ArrayList
成员变量。表示实际修改了几次exceptedModCount
:是ArrayList
内部类Itr
的成员变量。在ArrayList.iterator
方法时被初始化,只有通过迭代器对集合进行操作才会对其值进行修改Itr
:Iterator
一个实现,使用ArrayList.iterator
方法可以获取迭代器就是Itr
类的实例
总结
使用增强for循环,其实就是java使用的语法糖,其实实现的原理是借助Iterator进行元素的遍历。
如果在遍历的过程中,并通过Iterator,而是通过集合类自身的方法对集合进行添加/删除操作,在Iterator
进行下一次的遍历时,经检查发现有一次集合的修改操作并未通过自身进行,则可能发生了并发,而被其他线程执行,这就抛出了异常。
原文地址:https://blog.csdn.net/weixin_42396003/article/details/145300308
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!