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

Ger*_*cke 5 java iterator

我有一张地图.

Map<Integer,String> map = ...
Run Code Online (Sandbox Code Playgroud)

这个地图有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");
Run Code Online (Sandbox Code Playgroud)

现在我想迭代这个映射,并使用迭代器删除第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();
     }
  }
}
Run Code Online (Sandbox Code Playgroud)

从javadoc,我假设,删除的语义很明确.

但是根据地图的实现 - 即HashMap vs TreeMap,无论it.remove()是在之前还是之后 都有所不同entry.getValue().

对于HashMaps map = new HashMap<>(),行为是

...
remove(4, map); //output: four
//or
remove(5, map); //output: five
Run Code Online (Sandbox Code Playgroud)

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

System.out.println(entry.getValue());
it.remove();
Run Code Online (Sandbox Code Playgroud)

结果是

remove(4, map); //output: four
//or
remove(5, map); //output: five
Run Code Online (Sandbox Code Playgroud)

到目前为止这么好,但如果我访问该条目之前删除该元素:

it.remove();
System.out.println(entry.getValue());
Run Code Online (Sandbox Code Playgroud)

输出意外

remove(4, map); //output: five !!!
//or
remove(5, map); //output: five ok
Run Code Online (Sandbox Code Playgroud)

显然,it.remove()在的TreeMap修改Entries,因为TreeMap是由Entries和迭代器实际上返回地图的实际元素.并且根据树中的当前位置,Entry的内部引用指向下一个或当前(已移除)元素.

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

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

use*_*ica 2

来自Map.EntryJavadoc

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

来自Map.Entry.getValueJavadoc

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

禁止entry.getValue()拨打电话。it.remove()Java 不承诺尝试后会发生什么。您应该在删除条目之前检索该值。