computeIfPresent() is a Map method introduced in Java 8 that conditionally updates a value using a function — but only if the key already exists in the map. If the key is absent, nothing happens. It replaces the verbose containsKey() + put() pattern with a single, expressive call.


Method Signature

V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
  • key — the key to look up
  • remappingFunction — receives the key and current value; its return value becomes the new value
  • Returns — the new value if key was present; null if absent or function returned null
  • Side effect — if the function returns null, the entry is removed from the map

Basic Example

import java.util.HashMap;
import java.util.Map;

public class ComputeIfPresentExample {

    public static void main(String[] args) {
        Map<String, Integer> prices = new HashMap<>();
        prices.put("Sunglasses", 105);
        prices.put("Watch", 1501);
        prices.put("Wallet", 299);

        System.out.println("Before: " + prices);

        // "Watch" exists — price is doubled
        prices.computeIfPresent("Watch", (key, value) -> value * 2);

        // "Bag" doesn't exist — map is unchanged
        prices.computeIfPresent("Bag", (key, value) -> value * 2);

        System.out.println("After:  " + prices);
        // {Watch=3002, Sunglasses=105, Wallet=299}
    }
}

Output:

Before: {Watch=1501, Sunglasses=105, Wallet=299}
After:  {Watch=3002, Sunglasses=105, Wallet=299}

Removing an Entry by Returning null

If the remapping function returns null, the entry is deleted:

Map<String, Integer> stock = new HashMap<>();
stock.put("Apples", 10);
stock.put("Bananas", 5);
stock.put("Cherries", 20);

// Remove items with stock below 8
stock.computeIfPresent("Apples",   (k, v) -> v < 8 ? null : v);  // 10 >= 8, kept
stock.computeIfPresent("Bananas",  (k, v) -> v < 8 ? null : v);  // 5 < 8, removed
stock.computeIfPresent("Cherries", (k, v) -> v < 8 ? null : v);  // 20 >= 8, kept

System.out.println(stock);
// {Apples=10, Cherries=20}

Before vs. After Java 8

Old approach — three lines, two map lookups:

if (prices.containsKey("Watch")) {
    prices.put("Watch", prices.get("Watch") * 2);
}

Modern approach — one line, atomic:

prices.computeIfPresent("Watch", (k, v) -> v * 2);

Beyond being cleaner, the modern approach is also atomic on ConcurrentHashMap, which makes it correct under concurrent access — the old pattern is not.


Real-World Example: Updating a Frequency Map

Map<String, Integer> wordCount = new HashMap<>();
wordCount.put("java", 5);
wordCount.put("python", 3);
wordCount.put("kotlin", 7);

String[] wordsToUpdate = {"java", "rust", "python", "go"};

for (String word : wordsToUpdate) {
    wordCount.computeIfPresent(word, (k, v) -> v + 1);
}

System.out.println(wordCount);
// {java=6, python=4, kotlin=7} — "rust" and "go" were NOT added

Real-World Example: Applying a Selective Discount

Map<String, Double> cart = new HashMap<>();
cart.put("Laptop",   999.99);
cart.put("Mouse",     29.99);
cart.put("Keyboard",  79.99);
cart.put("Monitor",  349.99);

List<String> saleItems = List.of("Mouse", "Keyboard", "Headphones");

for (String item : saleItems) {
    // Apply 20% discount — "Headphones" not in cart, skipped
    cart.computeIfPresent(item, (k, v) -> Math.round(v * 0.8 * 100.0) / 100.0);
}

cart.forEach((item, price) ->
    System.out.printf("%-12s $%.2f%n", item, price));
// Laptop       $999.99
// Mouse        $23.99
// Keyboard     $63.99
// Monitor      $349.99

Thread-Safe Use with ConcurrentHashMap

computeIfPresent() is atomic on ConcurrentHashMap. The check and the update happen as a single operation — no other thread can modify the entry between them:

import java.util.concurrent.ConcurrentHashMap;

ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("counter", 0);

// Safe to call from multiple threads concurrently
concurrentMap.computeIfPresent("counter", (k, v) -> v + 1);

The old containsKey() + put() pattern is not thread-safe — another thread can insert or remove the key between your two calls.


Related Map Compute Methods

MethodWhen to Use
computeIfPresent(k, fn)Update an existing value; do nothing if key absent
computeIfAbsent(k, fn)Insert a new value; do nothing if key present
compute(k, fn)Always call fn; fn receives null if key absent
merge(k, v, fn)Combine a new value with an existing one, or insert if absent
put(k, v)Always set a value, regardless of whether key exists
putIfAbsent(k, v)Insert only if key absent; fixed value (no function)

Summary

Use computeIfPresent() when you need to update an existing map entry based on its current value, without the boilerplate of a containsKey() check. It's cleaner, more expressive, and thread-safe when used with ConcurrentHashMap.


Method Signature

public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
  • key — the key to look up
  • mappingFunction — receives the key; its return value is inserted as the new value
  • Returns — the existing value if the key was already present, or the newly computed value
  • Side effect — if the function returns null, no entry is inserted

Basic Example

import java.util.HashMap;
import java.util.Map;

public class ComputeIfAbsentExample {

    public static void main(String[] args) {
        Map<Integer, String> numbers = new HashMap<>();
        numbers.put(1, "one");
        numbers.put(2, "two");
        numbers.put(3, "three");

        System.out.println("Before: " + numbers);

        // Key 4 is absent — value will be computed and inserted
        numbers.computeIfAbsent(4, k -> "four");

        // Key 5 is absent — lambda shorthand
        numbers.computeIfAbsent(5, k -> "five");

        // Key 1 already exists — no change
        numbers.computeIfAbsent(1, k -> "ONE");

        System.out.println("After:  " + numbers);
    }
}

Output:

Before: {1=one, 2=two, 3=three}
After:  {1=one, 2=two, 3=three, 4=four, 5=five}

Key 1 remains "one"computeIfAbsent() never overwrites existing values.


Common Pattern: Map of Lists

computeIfAbsent() is especially useful for building a Map<K, List<V>> — the classic "group by" pattern:

import java.util.*;

public class GroupByExample {

    public static void main(String[] args) {
        List<String> words = List.of("apple", "ant", "banana", "avocado", "blueberry");

        Map<Character, List<String>> grouped = new HashMap<>();

        for (String word : words) {
            char firstLetter = word.charAt(0);
            // Create the list if this letter hasn't been seen yet
            grouped.computeIfAbsent(firstLetter, k -> new ArrayList<>()).add(word);
        }

        grouped.forEach((letter, list) ->
                System.out.println(letter + ": " + list));
    }
}

Output:

a: [apple, ant, avocado]
b: [banana, blueberry]

Without computeIfAbsent(), you'd need to check whether the list exists, create it if not, then add — three lines instead of one.


Before vs. After Java 8

Old approach:

if (!grouped.containsKey(firstLetter)) {
    grouped.put(firstLetter, new ArrayList<>());
}
grouped.get(firstLetter).add(word);

With computeIfAbsent():

grouped.computeIfAbsent(firstLetter, k -> new ArrayList<>()).add(word);

Related Map Compute Methods

MethodBehavior
computeIfAbsent(k, fn)Insert only if key is absent
computeIfPresent(k, fn)Update only if key exists
compute(k, fn)Always compute; handles both cases
getOrDefault(k, default)Read-only; returns default without inserting
putIfAbsent(k, v)Insert a fixed value if absent (no function)

Memoization with computeIfAbsent()

computeIfAbsent() is perfect for caching computed results — only run the expensive computation once per key:

Map<Integer, Long> fibCache = new HashMap<>();

long fibonacci(int n) {
    if (n <= 1) return n;
    return fibCache.computeIfAbsent(n, k -> fibonacci(k - 1) + fibonacci(k - 2));
}

System.out.println(fibonacci(40)); // 102334155

The function is called at most once per key. On subsequent calls with the same key, the cached value is returned immediately. This turns an exponential recursion into a linear one.


Thread-Safe Use with ConcurrentHashMap

computeIfAbsent() is atomic on ConcurrentHashMap — the check and insertion happen as a single operation. This is important in concurrent environments where two threads might try to initialize the same key simultaneously:

import java.util.concurrent.ConcurrentHashMap;

ConcurrentHashMap<String, List<String>> groupedResults = new ConcurrentHashMap<>();

// Safe to call from multiple threads simultaneously
groupedResults.computeIfAbsent("category-A", k -> new ArrayList<>()).add("item1");
groupedResults.computeIfAbsent("category-A", k -> new ArrayList<>()).add("item2");

With a regular HashMap, this pattern is not thread-safe — two threads could both call the mapping function and the second would overwrite the first's result. Always use ConcurrentHashMap for shared maps accessed from multiple threads.


computeIfAbsent() vs putIfAbsent()

Both insert a value only if the key is absent, but there's an important difference:

// putIfAbsent — the new ArrayList is ALWAYS created, even if the key exists
map.putIfAbsent(key, new ArrayList<>());

// computeIfAbsent — the lambda is ONLY called if the key is absent
map.computeIfAbsent(key, k -> new ArrayList<>());
MethodWhen is value computed?Takes a function?
computeIfAbsent(k, fn)Only if key absentYes — receives the key
putIfAbsent(k, v)Always (value evaluated before call)No — fixed value

For values that are cheap to create (like a constant string), putIfAbsent() is fine. For values that are expensive to create (like a new database connection or a populated list), always use computeIfAbsent() to avoid unnecessary work.


Summary

computeIfAbsent() shines when you need lazy initialization of map values — especially for Map<K, List<V>> or Map<K, Set<V>> grouping patterns and for memoization caches. Prefer it over putIfAbsent() when the value is expensive to create. Use it with ConcurrentHashMap for thread-safe lazy initialization.

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.

There are a few ways to remove all entries from a Java Map. The right choice depends on whether other parts of your code hold a reference to the same map object, and whether thread safety matters.


Method 1: clear() — Empties the Existing Map Object

clear() removes all key-value pairs from the map in-place. The map object itself remains — it's the same reference, now empty. All implementations of the Map interface support it: HashMap, TreeMap, LinkedHashMap, ConcurrentHashMap, and others.

import java.util.HashMap;
import java.util.Map;

public class ClearMapExample {

    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "one");
        map.put(2, "two");
        map.put(3, "three");
        map.put(4, "four");
        map.put(5, "five");

        System.out.println("Before: " + map);
        System.out.println("Size:   " + map.size());

        map.clear();

        System.out.println("After:  " + map);
        System.out.println("Size:   " + map.size());
    }
}

Output:

Before: {1=one, 2=two, 3=three, 4=four, 5=five}
Size:   5
After:  {}
Size:   0

After clear(), isEmpty() returns true and size() returns 0. The map is ready to be repopulated.


Method 2: Reassignment — Replace With a New Map

If the variable is local or only you hold a reference to it, replacing it with a new map is equally valid:

Map<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");

// Replace with a fresh empty map
map = new HashMap<>();

System.out.println(map); // {}

Important caveat: If another variable also points to the original map, that variable still sees the old entries. The reassignment only changes this reference, not the underlying object.

Map<Integer, String> original = new HashMap<>();
original.put(1, "one");

Map<Integer, String> alias = original; // both point to same object

original = new HashMap<>(); // only original changes reference

System.out.println(alias);    // {1=one} — alias still sees old data
System.out.println(original); // {} — new empty map

When in doubt, use clear() — it affects the shared object rather than just the local pointer.


clear() Across Map Implementations

The behavior of clear() is consistent across all standard Map implementations:

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

Map<String, Integer> hashMap = new HashMap<>();
Map<String, Integer> treeMap = new TreeMap<>();
Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();

hashMap.put("a", 1);
treeMap.put("b", 2);
linkedHashMap.put("c", 3);
concurrentMap.put("d", 4);

hashMap.clear();
treeMap.clear();
linkedHashMap.clear();
concurrentMap.clear();

System.out.println(hashMap.isEmpty());       // true
System.out.println(treeMap.isEmpty());       // true
System.out.println(linkedHashMap.isEmpty()); // true
System.out.println(concurrentMap.isEmpty()); // true

Thread Safety

If your map is accessed from multiple threads, the approach matters:

Map Typeclear() Thread-Safe?Notes
HashMapNoRequires external synchronization
Collections.synchronizedMap()YesSynchronized on the map object
ConcurrentHashMapYesInternally handles concurrent access
TreeMapNoRequires external synchronization

For a ConcurrentHashMap, clear() is safe to call from multiple threads. For a regular HashMap, always synchronize externally if other threads might access the map during the clear:

synchronized (map) {
    map.clear();
}

Checking if a Map is Already Empty

Use isEmpty() to check before operating on a map you expect to be empty — or to guard against redundant work:

if (!map.isEmpty()) {
    map.clear();
}

// Or simply — clear() on an empty map is a no-op, safe to call unconditionally
map.clear();

Calling clear() on an already-empty map is safe and does nothing. There's no need to check first.


clear() vs. Iterating and Removing

Before Java had clear(), you might have removed entries one by one with an iterator. This is verbose and much slower:

// Old way — DO NOT do this
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
    it.next();
    it.remove();
}

// Modern way — one method call
map.clear();

clear() is O(n) just like iterating, but its internal implementation is optimized and avoids iterator overhead.


Summary

Use clear() when you want to empty the existing map object in place — especially when other code holds a reference to the same map. Use reassignment (map = new HashMap<>()) only when you're certain no other variable shares a reference to the old map. For concurrent access, ConcurrentHashMap.clear() is safe without additional synchronization.

Java's Map interface doesn't extend Iterable directly, so you can't use a for-each loop on the map itself. Instead, you iterate over one of its three collection views: entrySet(), keySet(), or values(). Here are five practical methods.


Setup — Sample Map

import java.util.*;

Map<Integer, String> countries = new HashMap<>();
countries.put(1, "USA");
countries.put(2, "Germany");
countries.put(3, "Japan");
countries.put(4, "Brazil");
countries.put(5, "India");

Method 1: entrySet() with For-Each Loop

The most common and readable approach. Each Map.Entry gives you direct access to both key and value without a second lookup:

for (Map.Entry<Integer, String> entry : countries.entrySet()) {
    System.out.println(entry.getKey() + " → " + entry.getValue());
}

Output:

1 → USA
2 → Germany
3 → Japan
4 → Brazil
5 → India

This is the preferred approach when you need both key and value. It avoids the extra map.get(key) call that keySet() iteration requires.


Method 2: entrySet() with Iterator

Use an explicit Iterator when you need to remove entries during iteration — the only safe way to modify a map while iterating:

Iterator<Map.Entry<Integer, String>> iterator = countries.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<Integer, String> entry = iterator.next();
    System.out.println(entry.getKey() + " → " + entry.getValue());

    // Safe to remove — iterator.remove() doesn't throw ConcurrentModificationException
    if (entry.getKey() == 3) {
        iterator.remove();
    }
}

Never call map.remove() inside a for-each loop — it throws ConcurrentModificationException. An explicit iterator's remove() is the safe alternative.


Method 3: keySet() with For-Each Loop

Iterate over keys, then look up each value separately:

for (Integer key : countries.keySet()) {
    System.out.println(key + " → " + countries.get(key));
}

This works but performs an extra get() per entry. Use this when you only need the keys, or when the value lookup is intentional. For both key and value, entrySet() is more efficient.


Method 4: keySet() with Iterator

Iterator<Integer> keyIterator = countries.keySet().iterator();
while (keyIterator.hasNext()) {
    Integer key = keyIterator.next();
    System.out.println(key + " → " + countries.get(key));
}

Method 5: Java 8 forEach() — Most Concise

Java 8 added a forEach() method directly on Map that accepts a BiConsumer:

countries.forEach((key, value) ->
    System.out.println(key + " → " + value));

This is the cleanest syntax for read-only iteration. It's internally backed by entrySet(), so performance is identical. You can't call iterator.remove() inside forEach() — use method 2 if you need to modify the map during iteration.


Iterating Values Only

When you only need the values (not the keys), iterate values():

for (String country : countries.values()) {
    System.out.println(country);
}

Comparison

MethodAccess Key?Access Value?Remove During?Java Version
entrySet() for-eachYesYes (direct)No5+
entrySet() iteratorYesYes (direct)Yes5+
keySet() for-eachYesVia get()No5+
keySet() iteratorYesVia get()Yes5+
forEach() lambdaYesYes (direct)No8+
values() for-eachNoYesNo5+

Which Method Should You Use?

  • Default choice: forEach((key, value) -> ...) — cleanest syntax, Java 8+
  • Need to remove during iteration: entrySet().iterator() with iterator.remove()
  • Keys only: for (K key : map.keySet())
  • Values only: for (V value : map.values())
  • Pre-Java 8: entrySet() for-each

Summary

Iterate over a Map using one of its three views: entrySet() for both keys and values, keySet() for keys alone, or values() for values alone. For most modern code, map.forEach((k, v) -> ...) is the cleanest option. When you need to remove entries during iteration, use an explicit iterator — never map.remove() inside a for-each loop.


How to Sort HashMap in java

This article covers some of the aspects of sorting Map in Java. Java Map comes in different flavours, like HashMap, TreeMap, LinkedHashMap etc. TreeMap for instance will sort the data based on the keys. We can also pass a custom Comparator to sort based on the keys as per the custom sort algorithm.
We can have two requirements in terms of sorting, first one is sorting by Keys and second is Sorting by Values. Following examples demonstrates few approaches for sorting by key and sorting by value. Following examples uses Java Lambda and Stream api to sort Java HashMap instance.

Sort by Value

Map sort by value in revere order
Following code snippet sorts the map based on value in reverse order and populates a new map reverseSortedMap from the data.
//LinkedHashMap preserve the ordering of elements in which they are inserted
Map reverseSortedMap =  new LinkedHashMap();
//Use Comparator.reverseOrder() for reverse ordering
map.entrySet()
    .stream()
    .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) 
    .forEachOrdered(x -> reverseSortedMap.put(x.getKey(), x.getValue()));

Sort By Key

Map sort by key in revere order
Following code snippet sorts the map based on the keys in reverse order.
//LinkedHashMap preserve the ordering of elements in which they are inserted
Map reverseSortedMapByKey =  new LinkedHashMap();;
//Use Comparator.reverseOrder() for reverse ordering
map.entrySet()
    .stream()
    .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())) 
    .forEachOrdered(x -> reverseSortedMapByKey.put(x.getKey(), x.getValue()));
 

System.out.println("Sorted by Value Map : " + reverseSortedMapByKey);

Full Example

MapSortJava
public class MapSortJava {

  public static void main(String[] args) {

    Map<Integer, String> map = new HashMap<Integer, String>();
    map.put(101, "Tokyo");
    map.put(3, "New York");
    map.put(2, "San Francisco");
    map.put(14, "Los Angels");
    map.put(5, "Austin");

    System.out.println("Unsorted Map : " + map);
    
   // LinkedHashMap preserve the ordering of elements in which they are inserted
    Map<Integer, String> reverseSortedMap = new LinkedHashMap<Integer, String>();;
    // Use Comparator.reverseOrder() for reverse ordering
    map.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
        .forEachOrdered(x -> reverseSortedMap.put(x.getKey(), x.getValue()));
    System.out.println("Sorted by Value Map : " + reverseSortedMap);


    // LinkedHashMap preserve the ordering of elements in which they are inserted
    Map<Integer, String> reverseSortedMapByKey = new LinkedHashMap<Integer, String>();;
    // Use Comparator.reverseOrder() for reverse ordering
    map.entrySet().stream().sorted(Map.Entry.comparingByKey(Comparator.reverseOrder()))
        .forEachOrdered(x -> reverseSortedMapByKey.put(x.getKey(), x.getValue()));
    System.out.println("Sorted by Value Map : " + reverseSortedMapByKey);

  }
}
Output
Unsorted Map : 2 ==> San Francisco 3 ==> New York 101 ==> Tokyo 5 ==> Austin 14 ==> Los Angels Sorted by Value Map (Reverse) : 2 ==> San Francisco 3 ==> New York 101 ==> Tokyo 5 ==> Austin 14 ==> Los Angels Sorted by Value Map (Reverse) : 101 ==> Tokyo 14 ==> Los Angels 5 ==> Austin 3 ==> New York 2 ==> San Francisco
Summary of steps
  • Get the entry set by calling the Map.entrySet().
  • Get the entry set stream by calling stream() method.
  • Use the Map.Entry.comparingByValue() or Map.Entry.comparingByKey().
  • Call the sorted method with a Comparator.
  • call the terminal operation forEachOrdered to store the each entries in the new Map.

How to use custom comparator for TreeMap

This article covers some of the aspects of sorting Map in Java. Java Map comes in different flavors, like HashMap, TreeMap, LinkedHashMap etc. TreeMap for instance will sort the data based on the keys. We can also pass a custom Comparator to sort based on the keys as per the custom sort algorithm.
TreeMap sorts based on natural ordering of the keys if no custom Comparator is provided. To use a custom Comparator we need to pass the Comparator in the TreeMap Constructor.

Simple TreeMap

TreeMap without any Comparator
Following code creates a TreeMap and adds some data to it. After that we print the TreeMap. As No comparator is specified, the data is sorted by natural ordering of the keys.
TreeMap map = new TreeMap();
    map.put(1, "A");
    map.put(3, "C");
    map.put(2, "B");
    map.put(4, "D");
    map.put(5, "E");


    System.out.println("\nPrint Map ");
    map.forEach((a, b) -> {
      printKeyVal(a,b);
    });;
Print Map Key: 1 Value: A Key: 2 Value: B Key: 3 Value: C Key: 4 Value: D Key: 5 Value: E

TreeMap with Comparator

TreeMap with reverse order Comparator
In this case we are passing a built in Comparator to sort the keys reversely. From the result we can see that the data is sorted in reverse order of the keys.
System.out.println("\nPrint Map with Reverse Comparator");
TreeMap map2 = new TreeMap(Collections.reverseOrder());
    map2.putAll(map);
    map2.forEach((a, b) -> {
      printKeyVal(a, b);
 });
Print Map with Reverse Comparator Key: 5 Value: E Key: 4 Value: D Key: 3 Value: C Key: 2 Value: B Key: 1 Value: A

Custom Comparator

Following examples shows implementation of two custom Comparator, one with inner class second one with java 8 Lambda. Both the Comparator works exactly same, that is it sorts the data in reverse order.
With Inner Classes
Custom Comparator with Inner Class to sort the keys in reverse order.
Comparator orderByKeyDesc = new Comparator() {
@Override
 public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);
      }
};
Lambda Comparator.
Java 8 Lambda to implement Comparator
Comparator orderByKeyDesc2 = (Integer o1, Integer o2) -> o2.compareTo(o1);

Full Example

TreeMapCustomComparator
Full example with Custom Comparator that is passed to the TreeMap.
public class TreeMapCustomComparator {

  public static void main(String[] args) {

    TreeMap map = new TreeMap();
    map.put(1, "A");
    map.put(3, "C");
    map.put(2, "B");
    map.put(4, "D");
    map.put(5, "E");


    System.out.println("\nPrint Map ");
    map.forEach((a, b) -> {
      printKeyVal(a, b);
    });;

   
    System.out.println("\nPrint Map with Reverse Comparator");
    TreeMap map2 = new TreeMap(Collections.reverseOrder());
    map2.putAll(map);
    map2.forEach((a, b) -> {
      printKeyVal(a, b);
    });


    //Custom Comparator with Inner Class
    Comparator orderByKeyDesc = new Comparator() {
      @Override
      public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);
      }
    };

    //Custom Comparator with Lambda
    Comparator orderByKeyDesc2 = (Integer o1, Integer o2) -> o2.compareTo(o1);

    System.out.println("\nPrint Map with Custom Reverse Comparator Java Lambda");
    TreeMap map3 = new TreeMap(orderByKeyDesc2);
    map3.putAll(map);

    map3.forEach((a, b) -> {
      printKeyVal(a, b);
    });

  }

  /* Utility method to print key value pairs nicely */
  private static void printKeyVal(Object a, Object b) {
    System.out.print("Key: " + a + "  Value: " + b + "     ");
  }


}
Print Map Key: 1 Value: A Key: 2 Value: B Key: 3 Value: C Key: 4 Value: D Key: 5 Value: E Print Map with Reverse Comparator Key: 5 Value: E Key: 4 Value: D Key: 3 Value: C Key: 2 Value: B Key: 1 Value: A Print Map with Custom Reverse Comparator Java Lambda Key: 5 Value: E Key: 4 Value: D Key: 3 Value: C Key: 2 Value: B Key: 1 Value: A

Table of Content

Iterating Java Map

Java Map is an object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value. If we want to get the object stored at a particular key we can do so using the the get method.
But if we want to traverse all the objects, then we have different ways of doing the same.

Different Options

In Java we have the following four options to iterate over java map.
Map Iterator
Classic way of using the Iterator of the keySet.
//Iterator
Map map = new TreeMap();
System.out.println("Print using Iterator");
Iterator it = map.keySet().iterator();

while (it.hasNext()) {
  Integer k = it.next();
  String  v = map.get(k);
  System.out.print( "Key=" + k + " Value=" + v + "  ");
}
Java 8 forEach
We can use the forEach introduced in Java 8 to iterate over key and value.
//forFeach
Map map = new TreeMap();
System.out.println("\nPrint using Java 8 forEach");
map.forEach((k,v) -> System.out.print("Key=" + k + " Value=" + v + "  "));
For loop over the keyset
Using for loop over the key set, and then getting the respective value from the map.
//For loop over the keySet
Map map = new TreeMap();
System.out.println("\nPrint using for loop");
for (Integer k : map.keySet()) {
  String  v = map.get(k);
  System.out.print("Key=" + k + " Value=" + v + "  ");
}

Full Example

Full Java Class with all the above options to iterate over map.
MapIterationExample
package bootng.com.learn.collections;

public class MapIterationExample {
  public static void main(String[] args) {
    Map<Integer, String> map = new TreeMap<Integer, String>();
    map.put(1, "A");
    map.put(3, "C");
    map.put(2, "B");
    map.put(4, "D");
    map.put(5, "E");

    // Iterator
    System.out.println("Print using Iterator");
    Iterator<Integer> it = map.keySet().iterator();

    while (it.hasNext()) {
      Integer k = it.next();
      String v = map.get(k);
      System.out.print("Key=" + k + " Value=" + v + "  ");
    }

    // forFeach
    System.out.println("\nPrint using Java 8 forEach");
    map.forEach((k, v) -> System.out.print("Key=" + k + " Value=" + v + "  "));

    // For loop over the keySet
    System.out.println("\nPrint using for loop");
    for (Integer k : map.keySet()) {
      String v = map.get(k);
      System.out.print("Key=" + k + " Value=" + v + "  ");
    }

    // Stream
    System.out.println("\nPrint using stream");
    map.keySet().stream().forEach(key -> {
      System.out.print("Key=" + key + " Value=" + map.get(key) + "  ");
    });    
  }
}
Output
Print using Iterator
Key=1 Value=A  Key=2 Value=B  Key=3 Value=C  Key=4 Value=D  Key=5 Value=E  
Print using Java 8 forEach
Key=1 Value=A  Key=2 Value=B  Key=3 Value=C  Key=4 Value=D  Key=5 Value=E  
Print using for loop
Key=1 Value=A  Key=2 Value=B  Key=3 Value=C  Key=4 Value=D  Key=5 Value=E  
Print using stream
Key=1 Value=A  Key=2 Value=B  Key=3 Value=C  Key=4 Value=D  Key=5 Value=E  

LinkedHashMap

LinkedHashMap in Java stores key-value pairs and maintains the order of elements inserted. LinkedHashMap extends HashMap. The method removeEldestEntry in LinkedHashMap is used to delete the old entry in the map automatically. This method is triggered when we put values to the map.
removeEldestEntry() method is triggered when we put new items to map. It is a boolean method and accepts one parameter. We can override this method to decide whether and when to remove eldest entries from the map.

removeEldestEntry : What it does

Say we want to only keep a certain number of items in the LinkedHashMap, and when it reaches the upper limit we want to get rid of the oldest entries. We could write a custom method to delete the oldest entry when map.size() == upper_limit and call it before adding any items. removeEldestEntry does the same thing, allowing us to implement this logic without boilerplate code.
removeEldestEntry is checked by Java before adding any items to the map.

LinkedHashMap map;
map = new LinkedHashMap(10, 0.7f, false);
map.put(0, "A"); 
map.put(1, "B"); 
map.put(2, "C"); 
map.put(3, "D"); 
map.put(4, "E"); 
map.put(5, "F");

System.out.println(map); // {0=A, 1=B, 2=C, 3=D, 4=E, 5=F}
      

Example 2 : LinkedHashMap with removeEldestEntry

In the following example, we want to keep only 4 items in the map. When it exceeds 4, the oldest entries should be deleted.

LinkedHashMap map;

map = new LinkedHashMap(10, 0.7f, false) {
  protected boolean removeEldestEntry(Map.Entry eldest) {
    return size() > 4;
  }
};

map.put(0, "A"); 
map.put(1, "B"); 
map.put(2, "C"); 
map.put(3, "D"); 
map.put(4, "E"); 
map.put(5, "F");

System.out.println(map); // {2=C, 3=D, 4=E, 5=F}
      
Summary
  • removeEldestEntry by default returns false, meaning it will not remove any old items.
  • We can implement this method to delete older records.
  • removeEldestEntry is invoked while adding items to the map.
  • It is useful for implementing data structures similar to a cache.