【问题标题】:How do I iterate over (and make changes to) a collection that is the value of another collection如何迭代(并更改)作为另一个集合的值的集合
【发布时间】:2012-12-28 18:14:20
【问题描述】:

我有一个将字节映射到字节集的映射。我想浏览地图并对场景进行更改。

private HashMap<Byte, HashSet<Byte>> table;
...
Iterator<Entry<Byte, HashSet<Byte>>> it = table.entrySet().iterator();
while( it.hasNext() ) {
   Map.Entry<Byte, HashSet<Byte>> pairs = it.next();
   byte node = pairs.getKey();
   HashSet<Byte> hSet = pairs.getValue();
   Iterator<Byte> setIter = hSet.iterator();
   while( setIter.hasNext() ) {
      byte sNode = setIter.next();  // Throws a ConcurrentModificationException
      ...
   }
 }

当我尝试遍历子迭代器时,此代码会引发 ConcurrentModificationException。我应该怎么做才能在我的地图中迭代和更改这个集合?

【问题讨论】:

  • 你想做出什么样的改变?
  • 使用Guava HashMultimap 可能会更好。
  • 尝试模拟您的问题。但是代码对我来说工作得很好。您能发布任何其他详细信息吗?

标签: java collections hashmap hashset


【解决方案1】:

我认为您得到了例外,因为您在迭代期间修改了集合(在未包含在问题中的行中)。如果“快速失败”迭代器检测到集合的结构已更改,则会将其抛出。

请注意,此异常并不总是表示对象已被不同的线程同时修改。如果单个线程发出一系列违反对象约定的方法调用,则该对象可能会抛出此异常。例如,如果线程在使用快速失败迭代器迭代集合时直接修改集合,则迭代器将抛出此异常。

http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html

如果您只是在迭代时从集合中删除,则可以使用迭代器的 remove 方法,而不是 Set 方法。如果您还想在迭代时添加到集合中,则需要创建 Set 的副本,然后对其进行迭代(但这种情况不太可能,您可以在不迭代的情况下添加到集合中......)

【讨论】:

  • +1 表示问题不是由抛出异常的行引起的。
【解决方案2】:

尝试类似的方法:

for(Byte node : table.keySet()) {
   HashSet<Byte> hSet = table.get(node);
   Iterator<Byte> setIter = hSet.iterator();
   while( setIter.hasNext() ) {
      byte sNode = setIter.next(); 
      ...
   }
 }

如果您想修改hSet,最好的方法可能是循环遍历Set 的副本:

for(Byte node : table.keySet()) {
    HashSet<Byte> hSet = table.get(node);

    for (Byte sNode : new HashSet<Byte>(hSet)) {
        //do things which modifies the original hSet
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-02
    • 2015-09-07
    • 1970-01-01
    • 1970-01-01
    • 2016-08-19
    相关资源
    最近更新 更多