In Java development, maps are fundamental data structures for associating keys with values. A common requirement is displaying or processing Map entries in a sorted order. If you need to sort a Map by its natural keys, Java makes this simple: you can wrap the map inside a TreeMap, which maintains key-based ordering automatically.

However, sorting a Map by its values is much more challenging. Because the map's internal bucket structure is hashed and optimized around keys, there is no built-in TreeMap equivalent for value-based sorting. Instead, you must extract the map's entry set, sort the collection using a custom value comparator, and populate it back into an insertion-ordered collection representation. In this guide, we will walk through the classic list-based sorting approach and the modern, declarative Java 8 Stream API approach.

Real-World Analogy: The Phone Book Indexes

To visualize the difference between key sorting and value sorting, imagine managing a physical city phone directory:

  • Sorting by Key (Alphabetical Names): This is the default. The directory is structured by name (keys). Finding "John Doe" is easy because the pages are naturally ordered alphabetically.
  • Sorting by Value (Phone Numbers): Imagine you are tasked with sorting the entire phone book by phone numbers (values) from smallest to largest to find who has the lowest number. Because the book is structured by name, you cannot easily do this. You must copy every name-number pair onto separate index cards (extracting the entry set), sort those cards manually in a new stack (using a comparator), and write down the final sorted order in a brand-new notebook (preserving order in a LinkedHashMap).
This index card stack sorting represents the extra work required to sort map entries by value.

1. Classic Approach: List Transfer and Collections.sort()

Before Java 8, sorting a map by value required a manual, three-step imperative pipeline:

  1. Extract to List: Retrieve the entry set via map.entrySet() and pass it to a new ArrayList.
  2. Sort the List: Invoke Collections.sort() on the list, providing a custom Comparator that compares Map.Entry values.
  3. Collect to LinkedHashMap: Loop through the sorted list and insert each key-value pair sequentially into a LinkedHashMap to preserve the newly sorted insertion order.

Here is the classic pre-Java 8 method implementation for value sorting:

private static void sortByValuesWithoutStream(Map<String, Integer> map) {
    // 1. Copy entries to a list
    ArrayList<Map.Entry<String, Integer>> entries = new ArrayList<>(map.entrySet());
 
    // 2. Sort the entry list
    Collections.sort(entries, (o1, o2) -> {
        return o2.getValue().compareTo(o1.getValue()); // Descending order
    });
 
    // 3. Put elements back into an insertion-ordered LinkedHashMap
    LinkedHashMap<String, Integer> sortedMap = new LinkedHashMap<>();
    entries.forEach(entry -> sortedMap.put(entry.getKey(), entry.getValue()));
 
    System.out.println(sortedMap); // Prints sorted map representation
}

2. Modern Approach: The Java 8 Stream API

With the introduction of Java 8 Streams, this verbose workflow is compressed into a declarative, single-line pipeline. By streaming the entry set, applying Stream.sorted() with the built-in Map.Entry.comparingByValue() comparator, and collecting or displaying the values directly, the code becomes highly readable and concise.

Below is the modern Stream method showing inline comparison and traversal:

private static void sortByvaluesWithStream(Map<String, Integer> map) {
    map.entrySet().stream()
            // Sort entries using custom value comparator
            .sorted(Map.Entry.comparingByValue((o1, o2) -> o2.compareTo(o1))) 
            .forEach(entry -> System.out.print(entry.getKey() + "=" + entry.getValue() + " "));
}

Full Implementation Code

Below is the complete Java program comparing both sorting layouts:

package io.practise.map;
 
import java.util.*;
 
public class TestMapSorting {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("Abhishek", 95);
        map.put("Rahul", 12);
        map.put("Prateek", 50);
        map.put("Anil", 58);
 
        System.out.println("Classic Sorting Result:");
        sortByValuesWithoutStream(map);
 
        System.out.println("Stream Sorting Result:");
        sortByvaluesWithStream(map);
    }
}

Conclusion & Best Practices

Sorting a map by value is a common operational task. The classic approach using LinkedHashMap is perfect if you need to return a sorted map object. To collect a stream back into an ordered map representation, use Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new) to preserve the sorted insertion order.