Why can the iterator on map.vaules be used to remove the HashMap # Entry?

I am trying to delete an entire entry whose value is null . Code:

 Map<String, String> map = new HashMap<>(); map.put("one", null); map.put("two", null); map.put("three", "THREE"); Iterator iterator = map.values().iterator(); while (iterator.hasNext()) { if (iterator.next() == null) { iterator.remove(); } } for (Map.Entry<String, String> e : map.entrySet()) { System.out.println(e.getKey() + ":" + e.getValue()); } 

My iterator question is related to map.values , why can it delete the whole entry?

+5
source share
2 answers

Perhaps because Map#values returns a representation of the values supported by the map .

From the official value of Java-Doc of Map # :

Gets a view of the collection of values โ€‹โ€‹contained in this map. The collection is supported by the map, so changes to the map are reflected in the collection, and vice versa. [...] The collection supports the removal of elements, which removes the corresponding map from the map, through the operations Iterator.remove, Collection.remove, removeAll, keepAll and clear. It does not support add or addAll operations.


Please note that the AbstractMap class, from which most map implementations are distributed, has an additional field transient volatile Collection<V> values , and this is what you get there. Since you see that the collection is used internally by the Card, and therefore changes to it are also reflected on the card itself. See Also: AbstractMap Source Code


If you want to dwell in detail, take a look at the AbstractMap#values method in the source code. There they create a collection of values โ€‹โ€‹as a wrapper that runs on the original map. For example, its next method iterates over Entry<K, V> Map entries, but returns them only with Entry#getValue , etc.
In addition, the remove method, as you can see, is passed to the Entry<K, V> iterator, so at the end the end will be executed on the original map.

+8
source

The explanations were given by Zabuza, but since there is the right way to remove your elements, I write them:


To remove Entry with a null value, you can use Streams :

 map = map.entrySet() .stream() .filter(entry -> entry.getValue()!=null) .collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue)); 

Or in one line : map.entrySet().removeIf(e -> e.getValue()==null);

Or: map.values().removeIf(v -> v == null)

+2
source

Source: https://habr.com/ru/post/1270176/


All Articles