【问题标题】:Java - list iterator not working on IdentityHashMapJava - 列表迭代器不适用于 IdentityHashMap
【发布时间】:2017-11-20 06:08:26
【问题描述】:

我正在使用身份哈希映射来跟踪我之前在自定义序列化程序中看到的对象。我有一个 while 循环,我尝试在其中迭代地图中的条目。在方法调用addAllFields 期间,可能会将对象添加到映射的键集中。经过一些调试后,我注意到我的iterator.hasNext() 返回false,即使我知道自上次循环体执行以来对象已添加到地图中。我在这里做错了什么?

public Document serialize(Object obj) throws Exception {
    reset();
    addToMap(obj);
    Set<Object> keys = map.keySet();
    Iterator<Object> iterator = keys.iterator();
    while(iterator.hasNext()) {
        Object key = iterator.next();
        Element objectElement = createObjectElement(key.getClass().getName(), map.get(key));
        addAllFields(objectElement, key);
        document.getRootElement().addContent(objectElement);
    }
    return document;
}

【问题讨论】:

  • “我在这里做错了什么?” 在迭代时修改地图。 keySet​() 的 Javadoc 说:如果在对集合进行迭代时修改了地图,则迭代的结果是未定义
  • 是否还有另一个您知道的没有这种未定义行为的哈希映射?
  • ConcurrentHashMapkeySet() 的 Javadoc 说:视图的迭代器和拆分器是 weakly consistent,即保证遍历元素,因为它们在构造时恰好存在一次,并且可能(但不保证)反映后续的任何修改施工。

标签: java iterator


【解决方案1】:

您需要使用ListIterator,然后如果您也想迭代添加的元素,您需要反向执行整个操作:

ListIterator<Object> iter = keys.listIterator(keys.size());
while (iter.hasPrevious()){
    Object prev=iter.previous();
    // do your Element creation here
    // then use the iter.add() method
    iter.add(/*new object*/);
}

注意,您可能需要将密钥集包装在不同的集合类型中,因为并非所有都支持 ListIterator,并且可能需要将 iter 作为参数传递给 #addAllFields() 您可能还需要遍历条目集而不是 keySet

【讨论】:

  • 感谢您的潜在解决方案。可能是因为我需要使用不同的地图实现来保证某种排序?链接哈希图怎么样?
  • 我认为确切的解决方案取决于您在#addAllFields() 中添加的任何内容是否可以在处理时本身添加更多条目?我认为没有支持在迭代期间添加的 Map 实现,这会给您留下类似 List> l = new ArrayList(map.entrySet()); 的东西。 // V 是映射值类型 ListIterator> iter = l.listIterator();然后在我的回答中如上所述。最后,如果你真的需要更新map,那么你将不得不添加来自l的任何新条目
猜你喜欢
  • 2013-04-12
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
  • 2020-12-08
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
相关资源
最近更新 更多