1

与 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);
    }
}
4

4 回答 4

8

根据 javadoc

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

 transactionLogMap.remove(bigDecimal);

而不是在迭代器上for loop使用Iterator和调用 remove。

例子:

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

或者

您可以考虑使用ConcurrentHashMap

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

于 2012-07-30T14:04:58.470 回答
4

问题出在这几行

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

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

正确的解决方案是使用Iterator

Iterator<BigDecimal> it = transactionLogMap.keySet().iterator();//changed for syntax correctness
while (it.hasNext()) {
    BigDecimal bigDecimal = it.next();
    if(!inScopeActiveRegionIdSet.contains(bigDecimal)) {
        it.remove();
    }
}
于 2012-07-30T14:08:29.010 回答
2

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

你打电话时:

for(TypeX x: collectionOfX){ ... }

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

如果您需要在迭代期间从集合中删除项目,则需要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.
}
于 2012-07-30T14:09:12.637 回答
0

或者,如果inScopeActiveRegionIdSet尺寸更小,则迭代它可能会更短更快:

for (BigDecimal bigDecimal : inScopeActiveRegionIdSet) {
    transactionLogMap.remove(bigDecimal);
}
于 2012-07-30T14:18:28.287 回答