我有一张地图.
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的内部引用指向下一个或当前(已移除)元素.
但我不确定这是不是一个错误,或者这是故意的.如果是后者,我想知道背后的理由?
如果在迭代器返回条目后修改了支持映射,则映射条目的行为是未定义的,除非通过映射条目上的 setValue 操作
如果映射已从支持映射中删除(通过迭代器的删除操作),则此调用的结果是未定义的。
禁止entry.getValue()拨打电话。it.remove()Java 不承诺尝试后会发生什么。您应该在删除条目之前检索该值。