Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TreeMap iterator.remove() modifies the last Entry

Tags:

java

iterator

I have a Map.

Map<Integer,String> map = ...

The map has n elements (lets take for this example these 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");

Now I want to iterate over this map, and remove the n-th element using the iterator.

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();
     }
  }
}

From the javadoc, I'd assume, the semantics of the remove are well defined.

But depending on the implementation of the map - i.e. HashMap vs TreeMap there is a difference whether the it.remove() is done before or after entry.getValue().

for HashMaps map = new HashMap<>() the behavior is

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

for TreeMap map = new TreeMap<>() the behavior is same, when I remove the current entry from the iterator after I have accessed it:

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

results in

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

so far so good, but if I remove the element before I access the entry:

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

The output is unexpectedly

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

Apparently, the it.remove() of the TreeMap modifies the Entries, because the TreeMap is made up of Entries and the iterator actually returns the actual elements of the map. And depending on the current position in the tree, the internal references of the Entry point to the next or the current (removed) element.

But I'm not sure if this is a bug or if this is intentional. If the latter is the case, I wonder about the rationale behind?

Edit: Source code of TreeMap iterator.remove()

like image 787
Gerald Mücke Avatar asked Aug 24 '17 13:08

Gerald Mücke


People also ask

How do I remove the last element in TreeMap?

To remove the last entry of the TreeMap, use the pollLastEntry() method.

How do you remove elements from TreeMap?

TreeMap remove() Method in Java remove() is an inbuilt method of TreeMap class and is used to remove the mapping of any particular key from the map. It basically removes the values for any particular key in the Map. Parameters: The method takes one parameter key whose mapping is to be removed from the Map.

How do I iterate and delete a map?

While iterating, check for the key at that iteration to be equal to the key specified. The entry key of the Map can be obtained with the help of entry. getKey() method. If the key matches, remove the entry of that iteration from the HashMap using remove() method.

How to remove the first and last entry from a treemap?

Using pollFirstEntry () and pollLastEntry () methods: TreeMap has two method which can remove the first and last entry . pollFirstEntry () for removing the first entry and for last entry we use pollLastEntry ().

How to iterate a TreeMap in Java?

The TreeMap in Java is used to implement Map interface and NavigableMap along with the Abstract Class. We cannot iterate a TreeMap directly using iterators, because TreeMap is not a Collection. So we will have to use TreeMap.entrySet () method.

How to remove a key from a TreeMap in Java?

TreeMap remove() Method in Java. The java.util.TreeMap.remove() is an inbuilt method of TreeMap class and is used to remove the mapping of any particular key from the map. It basically removes the values for any particular key in the Map. Syntax: Parameters: The method takes one parameter key whose mapping is to be removed from the Map.

When to use traversal over a treemap object?

This method is most common and should be used if you need both map keys and values in the loop. Now let us see traversal over the entries in the TreeMap object.


1 Answers

From the Map.Entry Javadoc:

the behavior of a map entry is undefined if the backing map has been modified after the entry was returned by the iterator, except through the setValue operation on the map entry

And from the Map.Entry.getValue Javadoc:

If the mapping has been removed from the backing map (by the iterator's remove operation), the results of this call are undefined.

Calling entry.getValue() after it.remove() is forbidden. Java makes no promises about what will happen if you try it. You should retrieve the value before removing the entry.

like image 91
user2357112 supports Monica Avatar answered Oct 27 '22 01:10

user2357112 supports Monica