java - 如何在java中的map上保留两个迭代器并在没有ConcurrentModificationException的情况下删除它们之间的键
Posted
技术标签:
【中文标题】java - 如何在java中的map上保留两个迭代器并在没有ConcurrentModificationException的情况下删除它们之间的键【英文标题】:How to keep two iterators over map in java and remove keys in between without ConcurrentModificationException 【发布时间】:2013-02-26 08:09:46 【问题描述】:我必须处理Map <BitSet,List<List<Integer>> MyMap
if (key1 contains all of corresponding true bits of key2)
Remove from key2 all those values which are common with key1)
在此过程中,如果列表中的元素数量低于阈值(用户定义的正整数),则将其删除。此外,如果 Map 包含空列表,则删除相应的键。
我正在使用以下代码:
List<BitSet> keys = new ArrayList<>(MyMap.keySet());
ListIterator it1=keys.listIterator();
while(it1.hasNext())
BitSet key1=(BitSet)it1.next();
ListIterator it2=keys.listIterator(it1.nextIndex());
while(it2.hasNext())
BitSet key2=(BitSet)it2.next();
BitSet ankey=(BitSet)key1.clone();
ankey.and(key2);
if(ankey.equals(key1)) //key1 is subset and key2 is superset
if(removePoints(key1,key2))
it1.remove();
break;
else if(ankey.equals(key2))
if(removePoints(key2,key1))
it2.remove();
public static boolean removePoints(BitSet key1,BitSet key2)
List<List<Integer>> list1=MyMap.get(key1);
List<List<Integer>> list2=MyMap.get(key2);
Boolean ret=false;
for(int i=0;i<list1.size();i++)
List<Integer> sublist1=list1.get(i);
for(int j=0;j<list2.size();j++)
List<Integer> sublist2=list2.get(j);
sublist1.removeAll(sublist2);
if(sublist1.isEmpty())
break;
if(sublist1.size()<=THRESHOLD)
list1.remove(sublist1);
if( list1.isEmpty())
MyMap.remove(key1);
ret=true;
return ret;
但程序报错:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification
at java.util.ArrayList$Itr.next
另外,不确定这是否是有效的编码方式?由于地图包含约 2000 个条目。请指教。
【问题讨论】:
【参考方案1】:ConcurrentModificationException
可能会在创建 Iterator
之后修改基础集合时发生,并且该修改不是通过 Iterator
本身完成的。
在您编写的代码中,只有一个地方会发生这种情况:it1
和 it2
之间的交互,它们是同一集合上的迭代器。任何时候你调用remove
时,另一个会在你下次调用next
时中断。
有多种方法可以解决此问题,但一种方法是将要从“关键”集合中删除的内容与该集合的迭代分开,如下所示:
List<BitSet> allKeys = new ArrayList<>(MyMap.keySet());
List<BitSet> removedKeys = new ArrayList<>();
for (ListIterator<BitSet> it1 = allKeys.listIterator(); it1.hasNext(); )
BitSet key1 = it1.next();
for (ListIterator<BitSet> it2 = allKeys.listIterator(it1.nextIndex()); it2.hasNext(); )
BitSet key2 = it2.next();
BitSet ankey=(BitSet)key1.clone();
ankey.and(key2);
if(ankey.equals(key1)) //key1 is subset and key2 is superset
if(removePoints(key1,key2))
removedKeys.add(key1);
break;
else if(ankey.equals(key2))
if(removePoints(key2,key1))
removedKeys.add(key2);
break;
allKeys.removeAll(removedKeys);
allKeys
然后将处于您期望的状态。我假设稍后您会想致电MyMap.keySet().retainAll()
或类似的电话。
【讨论】:
【参考方案2】:您不能在地图的 keySet 上使用 iterator.remove(),因为它只是地图内部结构的“视图”。
但是您可以在映射的 entrySet() 上使用迭代器,其中每个元素都是 Map.Entry 的一个实例,其中包含所有映射条目(键/值对)。您可以在此迭代器上调用 iterator.remove(),这将有效地从映射中删除相应的键/值对。
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(Integer.valueOf(0), "0");
map.put(Integer.valueOf(1), "1");
map.put(Integer.valueOf(2), "2");
map.put(Integer.valueOf(3), "3");
map.put(Integer.valueOf(4), "4");
System.out.println(map);
Iterator<Map.Entry<Integer, String>> entryIter = map.entrySet().iterator();
while (entryIter.hasNext())
Map.Entry<Integer, String> entry = entryIter.next();
if (entry.getKey().intValue() % 2 == 0)
entryIter.remove();
System.out.println(map);
希望对你有帮助。
问候
【讨论】:
您对Map.iterator().remove()
的看法不正确,至少在一般情况下如此。 The interface specifies 支持删除,但不支持添加。以上是关于java - 如何在java中的map上保留两个迭代器并在没有ConcurrentModificationException的情况下删除它们之间的键的主要内容,如果未能解决你的问题,请参考以下文章