I'm trying to remove all the entry of which the value is null
. The code is:
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 question is iterator
is bind to map.values
, why it can remove the whole entry?
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.
@HDave It's possible using a method like Map. remove (Object key) , but should not be done during iteration.
You should always use Iterator's remove() method to remove any mapping from the map while iterating over it to avoid any error.
HashMap remove() Method in Java HashMap. remove() is an inbuilt method of HashMap 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.
It is possible because Map#values
returns a view of the values that is backed by the map.
From the official Java-Doc of Map#values:
Returns a Collection view of the values contained in this map. The collection is backed by the map, so changes to the map are reflected in the collection, and vice-versa. [...] The collection supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Collection.remove, removeAll, retainAll and clear operations. It does not support the add or addAll operations.
Note that the AbstractMap
class, from which most map implementations extend, has an extra field transient volatile Collection<V> values
and that is exactly what you will get there. As you see the collection is internally used by the Map and thus changes on it are also reflected on the Map itself. See also: Source code of AbstractMap
If you like to go in detail, take a look at the AbstractMap#values
method in the source code. There they create the values-collection as a wrapper that operates on the original map. For example its next
method iterates on the entries Entry<K, V>
of the Map but only return their value with Entry#getValue
and so on.
Also the remove
method, as you can see, gets passed over to the iterator of Entry<K, V>
, thus the remove will in the end be executed on the original map again.
Explanations have been given by Zabuza, but because there is proper way to remove your elements, I write them :
To remove Entry
with 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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With