天天看点

JAVA集合遍历增删 并发修改异常 java.util.ConcurrentModificationException

集合遍历增删 并发修改异常

想要在循环遍历的过程中删除集合中的元素,问题描述如下

// 遍历map集合(UO_table),对于不满足条件1 "支持度"的项集,直接从UO_table中删除
for(ItemPair itempair : UO_table.keySet()) {
	if(uo_list.size() < Info.min_sup){
		UO_table.remove(itempair);
	}
}
           

以上代码会出现并发修改异常

JAVA集合遍历增删 并发修改异常 java.util.ConcurrentModificationException

并发修改异常: 当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection(来自java API),从这里可以看出迭代器和集合是在不同线程里的。

查看资料知道了,迭代器其实在另外一个线程复制了一个一摸一样的集合进行遍历的。当用集合的remove方法删除元素时,迭代器是不会知道的,所以就会抛出异常。

修改1:用一个集合存储需要删除的记录,再remove()

ArrayList<ItemPair> listTemPairs =new ArrayList<ItemPair>();  //用一个ArrayList存储需要删除的记录
  //遍历UO_table中的元素
for(ItemPair itempair : UO_table.keySet()) {
	if(uo_list.size() < Info.min_sup){
		listTemPairs.add(itempair);
	}
}
//官方并没有实现map的removeAll方法,所以要用for()循环删除
for(ItemPair itemPair:listTemPairs) {
	UO_table.remove(itemPair);
}
           

修改2:用一个集合存储需要删除的记录,再remove()

Iterator<ItemPair> iterator = UO_table.keySet().iterator();   //引用迭代器
while(iterator.hasNext()) {    //利用迭代器进行遍历
	ItemPair itempair = iterator.next();
	if(uo_list.size() < Info.min_sup){
		iterator.remove();      
	}
           

问题2:集合遍历增删报错

集合遍历的时候和长度有关,如果一边遍历集合一边增删,会导致长度size变化,规则发生变化,会报错。

Exception in thread “main” java.util.Concurat java.util.HashMap$HashIterator.nextEntry
for (Cat cat : set) {
     if ("花花".equals(cat.getName())) {
       set.remove(cat);
     }
}
           

在单步调试中,此处cat.getName()已经获得“花花”,执行到set.remove(cat)时,是成功的,set.size 由原来3变为了2,但是再执行下一步时,直接报错,程序中断。

注意:这里的集合是无序的,但是在使用的时候,如果remove的对象是最后一个,那么不会报错,如果是前面的,就会涉及size变化,导致报错。

方案1: 删除后 break

由于此处是set集合,所以每个元素均为唯一,如果匹配出的数据为1个的话,直接在set.remove()后加break跳出即可。

for (Cat cat : set) {
     if ("花花".equals(cat.getName())) {
       set.remove(cat);
       break;
     }
}
           

方案2:集合存储删除元素 + removeAll()

如果匹配出的数据不唯一,有很多条,那么上面的方法就不可行了。

解决办法:采用removeAll 方法,用大集合减去小集合的方式得到结果。将匹配得到的cat对象,先存入set1中,再用set集合减去set1集合即可。

Set<Cat> set1=new HashSet<Cat>();
for (Cat cat : set) {
      if (cat.getMonth()<5) {
          set1.add(cat);
          }
}
set.removeAll(set1);
           

方案3:用while和迭代器遍历

但是这里删除的时候是调用集合的remove方法,不带参数,此处应该是不会涉及到size问题。此时,就可以删除,而且遍历成功。

it = set.iterator();
while (it.hasNext()) {
  Cat d = it.next();
  if ("花花".equals(d.getName())) {
        it.remove();
      }
}
           

原文链接:https://blog.csdn.net/ggwxk1990/article/details/77688195

继续阅读