我在使用 HashMap 时抛出 java.util.ConcurrentModificationException

Posted

技术标签:

【中文标题】我在使用 HashMap 时抛出 java.util.ConcurrentModificationException【英文标题】:I am getting java.util.ConcurrentModificationException thrown while using HashMap 【发布时间】:2012-07-28 05:15:19 【问题描述】:

与HashMap中的元素相比,如何删除下面代码中的键值对?

Map<BigDecimal, TransactionLogDTO> transactionLogMap = new HashMap<BigDecimal, TransactionLogDTO>();
for (BigDecimal regionID : regionIdList) // Generation new logDTO
                                            // objects for each in scope
                                            // region
    transactionLogMap.put(regionID, new TransactionLogDTO());

Set<BigDecimal> inScopeActiveRegionIdSet = new HashSet<BigDecimal>();

for (PersonDTO personDTO4 : activePersons) 

    inScopeActiveRegionIdSet.add(personDTO4.getRegion());



for (BigDecimal bigDecimal : transactionLogMap.keySet()) 
    if (!inScopeActiveRegionIdSet.contains(bigDecimal)) 
        transactionLogMap.remove(bigDecimal);
    

【问题讨论】:

【参考方案1】:

或者,如果inScopeActiveRegionIdSet 的大小更小,那么迭代它可能会更短更快:

for (BigDecimal bigDecimal : inScopeActiveRegionIdSet) 
    transactionLogMap.remove(bigDecimal);

【讨论】:

【参考方案2】:

问题出在这几行

for (BigDecimal bigDecimal : transactionLogMap.keySet()) 
    if(!inScopeActiveRegionIdSet.contains(bigDecimal)) 
        transactionLogMap.remove(bigDecimal);
    

当您调用transactionLogMap.remove 时,您正在遍历transactionLogMap,同时还直接修改底层Collection,这是不允许的,因为增强的for 循环无法看到这些更改。

正确的解决方法是使用Iterator:

Iterator<BigDecimal> it = transactionLogMap.keySet().iterator();//changed for syntax correctness
while (it.hasNext()) 
    BigDecimal bigDecimal = it.next();
    if(!inScopeActiveRegionIdSet.contains(bigDecimal)) 
        it.remove();
    

【讨论】:

【参考方案3】:

根据 javadoc

ConcurrentModificationException 可能会被检测到对象的并发修改的方法抛出,而这种修改是不允许的

 transactionLogMap.remove(bigDecimal);

使用Iterator 代替for loop 并在迭代器上调用remove。

例子:

Iterator iter = transactionLogMap.keySet().iterator();
while(iter.hasNext())

iter.remove();

您可以考虑使用ConcurrentHashMap

注意:输入代码,作为参考。可能存在语法错误。

【讨论】:

【参考方案4】:

在迭代集合时,您不能从集合中删除项目。这会导致您遇到异常。

当你打电话时:

for(TypeX x: collectionOfX) ... 

幕后发生的事情是,您正在为 collectionOfX 创建一个迭代器,并进行迭代,直到您明确地从循环中中断或迭代器的 hasNext() 为 false。

如果您需要在迭代期间从集合中删除项目,则需要将 foreach 构造替换为对迭代器的显式调用。比如:

Iterator<BigDecimal> iter = transactionLogMap.keySet().iterator();
while(iter.hasNext()) 
   BigDecimal bDecimal = iter.next();
   ...
   iter.remove(); //this will remove the current item from the collection, without raising an exception.

【讨论】:

以上是关于我在使用 HashMap 时抛出 java.util.ConcurrentModificationException的主要内容,如果未能解决你的问题,请参考以下文章

我在 Flutter 中遇到了一个问题:在构建 TextField 时抛出了以下断言,它使我遇到了一个奇怪的问题

“未处理的异常:NoSuchMethodError:在 null 上调用了 getter 'iterator'。”当我在颤振中使用 google_maps_polyline 插件时抛出

Scrapy 使用 crawlerprocess 运行时抛出错误

实体框架在使用 Find 方法时抛出异常

IOS UICollectionView 在使用两个集合视图时抛出断言

使用 NSubstitute 模拟出现问题时抛出异常的方法