TreeMap iterator.remove()修改最后一个Entry

时间:2017-08-24 13:53:11

标签: java iterator

我有一张地图。

Map<Integer,String> map = ...

地图有n个元素(这个例子就是这些9)

  map.put(1,"one");
  map.put(2,"two");
  map.put(3,"three");
  map.put(4,"four");
  map.put(5,"five");
  map.put(6,"six");
  map.put(7,"seven");
  map.put(8,"eigth");
  map.put(9,"nine");

现在我想迭代这个地图,并使用迭代器删除第n个元素。

private void remove(int num, final Map<Integer, String> map) {

  Iterator<Map.Entry<Integer,String>> it = map.entrySet().iterator();
  Map.Entry<Integer,String> entry;
  while(it.hasNext()){

     entry = it.next();

     if(Integer.valueOf(num).equals(entry.getKey())){
        it.remove();
        System.out.println(entry.getValue());
        // vs
        // System.out.println(entry.getValue());
        // it.remove();
     }
  }
}

从javadoc,我假设,删除的语义已经很好地定义。

但是根据地图的实现 - 即HashMap vs TreeMap,{/ 1>}在之前完成之后是 {{1} }。

对于HashMaps it.remove(),行为是

entry.getValue()

对于TreeMap map = new HashMap<>()行为是相同的,当我在访问它之后从迭代器中删除当前条目时:

...
remove(4, map); //output: four
//or
remove(5, map); //output: five

结果

map = new TreeMap<>()

到目前为止一切顺利,但如果我在之前移除元素,我会访问该条目:

System.out.println(entry.getValue());
it.remove();

输出意外

remove(4, map); //output: four
//or
remove(5, map); //output: five

显然,it.remove(); System.out.println(entry.getValue()); 的{​​{1}}会修改remove(4, map); //output: five !!! //or remove(5, map); //output: five ok ,因为it.remove()TreeMap组成,而迭代器实际上返回了实际的元素的地图。并且根据树中的当前位置,Entry的内部引用指向下一个或当前(已删除)元素。

但我不确定这是否是一个错误,或者这是否是故意的。如果是后者,我想知道背后的理由吗?

编辑: 源代码TreeMap iterator.remove()

2 个答案:

答案 0 :(得分:2)

来自Map.Entry Javadoc

  

如果在迭代器返回条目后修改了支持映射,则映射条目的行为是未定义的,除非通过映射条目上的setValue操作

来自Map.Entry.getValue Javadoc

  

如果映射已从支持映射中删除(通过迭代器的删除操作),则此调用的结果未定义。

禁止在entry.getValue()之后致电it.remove()。如果您尝试将会发生什么,Java不做任何承诺。您应该在删除条目之前检索该值。

答案 1 :(得分:0)

这是一个部分答案,但希望能让其他人知道如何提供更准确的答案。

假设您对Iterator#next()的通话会返回位于基础地图顶部的视图,

然后,当从地图中删除基础地图条目后,尝试访问值时,我们可能会得到一些未定义的行为,这可能不足为奇。

while (it.hasNext()) {
    entry = it.next();

    if (Integer.valueOf(num).equals(entry.getKey())) {
        it.remove();
        // the object which 'entry' points to is already removed
        // what is this pointing to?
        System.out.println(entry.getValue());
   }
}

根据您自己的观察,行为似乎是Map具体实施,暗示 执行特定地图涉及哪种行为