How to remove entries from java map based on values

Removing map entries by value (rather than by key) requires a slightly different approach than map.remove(key). Java provides clean, expressive ways to do this using the map's values collection.


The Setup

All examples below use this map:

import java.util.*;

Map<Integer, String> inventory = new HashMap<>();
inventory.put(1, "apple");
inventory.put(2, "banana");
inventory.put(3, "cherry");
inventory.put(4, "banana");
inventory.put(5, "date");

Goal: remove all entries where the value is "banana" (keys 2 and 4).


Method 1: removeIf() on values()

The cleanest, most expressive approach:

inventory.values().removeIf("banana"::equals);

System.out.println(inventory);
// {1=apple, 3=cherry, 5=date}

map.values() returns a live view of the map's values. Modifying it (including removing) directly modifies the underlying map. removeIf() accepts a predicate and removes all matching entries.

With a lambda:

inventory.values().removeIf(value -> value.equals("banana"));

Method 2: removeAll() on values()

Removes all entries matching any value in a given collection:

inventory.values().removeAll(Collections.singleton("banana"));

Collections.singleton("banana") creates a single-element set containing "banana". This is equivalent to removeIf("banana"::equals) but useful when you want to remove multiple distinct values at once:

// Remove all entries with value "banana" OR "cherry"
inventory.values().removeAll(Set.of("banana", "cherry"));

Method 3: entrySet() with removeIf()

Use this when your removal condition depends on both the key and the value:

// Remove all entries where the key is even AND the value starts with "b"
inventory.entrySet().removeIf(entry ->
        entry.getKey() % 2 == 0 && entry.getValue().startsWith("b"));

This is the most flexible approach for complex conditions.


Method 4: Iterator (Pre-Java 8)

For environments that can't use lambdas:

Iterator<Map.Entry<Integer, String>> it = inventory.entrySet().iterator();
while (it.hasNext()) {
    Map.Entry<Integer, String> entry = it.next();
    if ("banana".equals(entry.getValue())) {
        it.remove(); // safe removal during iteration
    }
}
Do not use map.remove() inside a for-each loop — it will throw ConcurrentModificationException. The iterator's remove() method is the safe way to delete during iteration.

Comparison

MethodReadable?Complex conditions?Java version
values().removeIf()ExcellentValue onlyJava 8+
values().removeAll()GoodMultiple valuesJava 8+
entrySet().removeIf()GoodKey + valueJava 8+
IteratorVerboseKey + valueAll

Removing Null Values

To remove all entries where the value is null, the same removeIf() approach works — but use Objects.isNull() instead of .equals() to avoid a NullPointerException:

import java.util.Objects;

Map<String, String> config = new HashMap<>();
config.put("host", "localhost");
config.put("port", null);
config.put("user", "admin");
config.put("pass", null);

config.values().removeIf(Objects::isNull);

System.out.println(config); // {host=localhost, user=admin}

Calling "banana"::equals on a null value would throw a NullPointerException, so always use Objects::isNull or a null-safe predicate when nulls are possible.


Producing a New Filtered Map (Without Mutating the Original)

All the methods above modify the map in-place. If you want to keep the original and produce a new filtered map, use a stream:

Map<Integer, String> filtered = inventory.entrySet()
        .stream()
        .filter(entry -> !entry.getValue().equals("banana"))
        .collect(Collectors.toMap(
            Map.Entry::getKey,
            Map.Entry::getValue
        ));

System.out.println(inventory); // original unchanged
System.out.println(filtered);  // {1=apple, 3=cherry, 5=date}

This is the right approach when the original map must remain intact — for example, when it's a read-only view shared across multiple parts of your application.


Pitfall: Unmodifiable Maps

If your map was created with Map.of(), Map.copyOf(), or Collections.unmodifiableMap(), all the removal methods above will throw UnsupportedOperationException:

// This map is unmodifiable — removal will fail
Map<Integer, String> immutable = Map.of(1, "apple", 2, "banana");
immutable.values().removeIf("banana"::equals); // UnsupportedOperationException!

// Make a mutable copy first
Map<Integer, String> mutable = new HashMap<>(immutable);
mutable.values().removeIf("banana"::equals);

If you receive a map from an external source and don't know whether it's mutable, wrap it in new HashMap<>(map) before attempting any removal.


Summary

For most cases, values().removeIf(value -> ...) is the cleanest option. When you need to check both key and value, use entrySet().removeIf(entry -> ...). Use Objects::isNull when removing null values. If you need to preserve the original, produce a new filtered map with a stream instead of mutating. Avoid modifying the map inside a for-each loop — always use removeIf() or an explicit iterator.

No comments :

Post a Comment

Please leave your message queries or suggetions.

Note: Only a member of this blog may post a comment.