List 递归删除元素
在使用list迭代器移除元素的时候,如果存在递归调用就会报如下错
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at com.sl.jvm.dome.aop.jit.Test.test(Test.java:25)
at com.sl.jvm.dome.aop.jit.Test.main(Test.java:15)
如下例子
public class Test {
public static void main(String[] args){
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b2");
list.add("c");
list.add("e");
test(list);
}
private static void test(List<String> list) {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String s = iterator.next();
if("a".equals(s) || "c".equals(s)){
iterator.remove();
}
if("b".equals(s)){
iterator.remove();
test(list);
}
if("e".equals(s)){
break;
}
}
}
}
运行就会报如上的错,这个错发生的地方在
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
在list操作之前比如next, remove, add等操作都会调用checkForComodification方法。
modCount : 在创建list的初始化, 用来记录list的修改次数。添加,删除值都会+1.
expectedModCount : 在创建 迭代器的时候初始化,会把modCount的值复值给expectedModCount。
这两个值主要使用Fail-Fast 机制 ,在多线程的环境下防止有其他线程修改list中的数据。
在这里报ConcurrentModificationException错是因为递归的时候,这一次递归调用list.iterator()初始化了expectedModCount的值,在这次递归中修改了expectedModCount和modCount的值,这次递归处理完,回到上一次递归,但是上一次递归的expectedModCount的值没有涨上去,modCount的值已经涨上去了,导致modCount != expectedModCount
处理方法
目前有两种处理方法
1. 每次循环的时候刷新expectedModCount, 调用list.iterator()初始化expectedModCount。改成 如下
private static void test(List<String> list) {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
iterator = list.iterator();
String s = iterator.next();
if("a".equals(s) || "c".equals(s)){
iterator.remove();
}
if("b".equals(s)){
iterator.remove();
test(list);
}
if("e".equals(s)){
break;
}
}
}
2.递归的时候传入Iterator, 不让其重新初始化,就能保持expectedModCount和modCount一致。 改成如下
private static void test(Iterator<String> iterator) {
while (iterator.hasNext()){
String s = iterator.next();
if("a".equals(s) || "c".equals(s)){
iterator.remove();
}
if("b".equals(s)){
iterator.remove();
test(iterator);
}
if("e".equals(s)){
break;
}
}
}