list for 循环报错 ConcurrentModificationException
- 1、案例一
- 背景
下面代码执行报错 ConcurrentModificationException
for (String s : list) {
list.remove(s);
}
- 分析
java.util.ArrayList.Itr#checkForComodification() 方法报的错。
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
(1)foreach方式遍历元素的时候,生成iterator,然后使用iterator遍历。
在生成iterator的时候,会设置expectedModCount参数,初始值为list的个数,此时modCount和exceptedModCount相等。
如果在遍历过程中删除元素,modCount+1,但是exceptedModCount不变,此时modCount和exceptedModCount不一致,就会抛出ConcurrentModificationException异常。
(2)使用iterator直接遍历,使用iterator的remove方法(Iterator子类:java.util.ArrayList.Itr)则正常,因为iterator的remove方法会在内部调用List的remove方法,并且会修改excepedModCount的值,
使modCount和exceptedModCount相等,因此会正常运行
- 解决
使用迭代器遍历
for(Iterator<String> i = list.iterator(); i.hasNext(); ) {
String item = i.next();
i.remove(); //这里调用迭代器的rermove方法而不是集合的remove方法
}
或使用
for (int i =0 ; i < list.size(); i++) {
String s = list.get(i);
list.remove(s);
}
java.util.ArrayList.Itr中的remove方法:
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount; // 修改excepedModCount的值
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
- 2、案例二
- 背景
某个方法中有以下两个操作:
方法中有一个list 的 forEach 循环,在此操作前,有一个对list中的元素进行删除操作的异步方法。具体如下:
public static void test(List<String> list) throws Exception {
// 异步方法
ThreadPoolUtil.getInstance().execute(() -> {
list.removeIf(obj -> Objects.equals(obj,"55"));
});
//forEach 循环
for (String s : list) {
//
}
}
- 报错
list for 循环偶尔报错:ConcurrentModificationException
- 分析
原因同上
- 解决
public static void test(List<String> list) throws Exception {
// 异步方法
ThreadPoolUtil.getInstance().execute(() -> {
for(Iterator<String> i = list.iterator(); i.hasNext(); ) {
String item = i.next();
if(Objects.equals(item,"55")){
i.remove();
}
}
});
//forEach 循环
for (String s : list) {
//
}
}
或使用
public static void test(List<String> list) throws Exception {
// 异步方法
ThreadPoolUtil.getInstance().execute(() -> {
for (int i =0 ; i < list.size(); i++) {
String s = list.get(i);
if(Objects.equals(item,"55")){
list.remove(s);
}
}
});
//forEach 循环
for (String s : list) {
//
}
}