A standard Java Map (like a HashMap) is designed for fast lookups, but it does not guarantee any order of its elements. Sorting Map entries by their keys is easy, but sorting Map entries by their values requires converting the map entries into a stream, applying a comparator, and collecting the ordered elements back into a Map structure that remembers insertion order.

Let's look at how we sort Map values using a simple leaderboard wall analogy.

Illustration of streaming, sorting by value descending, and collecting in LinkedHashMap
Real-World Analogy: The Leaderboard Wall

Imagine you run a company. You have a folder (the unsorted HashMap) containing records matching salary numbers to Employee cards (e.g. key `500` pointing to Employee `S1`). Because they are inside a folder, they are shuffled in no particular order.

You want to display a sorted ranking wall (the leaderboard) from highest salary to lowest:

  • You pull the cards out of the folder and slide them onto a conveyor belt one-by-one (converting map entries to a Stream).
  • As the cards move, a sorting manager compares their salaries (the values) and arranges them in descending order (using Map.Entry.comparingByValue(...)).
  • Finally, you pin the sorted cards onto a display board that holds them in the exact order they arrive (collecting them into a LinkedHashMap). Now, anyone looking at the wall sees the employees ordered perfectly by their salaries!

Walkthrough of the Main Method Scenario

Let's trace how the program executes step-by-step from the entry point of the main method:

Step 1: Instantiating the Map and Employees

The program sets up a HashMap and registers four employee cards with their salaries as the key:

Map<Integer, TestEmployee> salaryEmployeeMap = new HashMap<>();
salaryEmployeeMap.put(500, new TestEmployee(500, "S1", 1));
salaryEmployeeMap.put(800, new TestEmployee(800, "S2", 2));
...
Step 2: Conveyor Belt Stream Setup

The program enters the sorting function and starts a Java Stream pipeline:

salaryEmployeeMap.entrySet().stream()

This retrieves the key-value entries of the Map and places them into the stream conveyor belt.

Step 3: Comparing and Sorting by Value

The stream sorts the entries based on their employee values:

.sorted(Map.Entry.comparingByValue((o1, o2) -> Integer.compare(o2.getSalary(), o1.getSalary())))

The comparator compares the salary of the second object o2 against the first o1. Since o2 is placed first in the comparison, it forces a descending sort order (highest salary first):

  • S4 (900) vs. S2 (800) -> S4 is larger, moves to the front.
  • The resulting sorted order of employee names becomes: S4, S2, S1, S3.
Step 4: Pinning to LinkedHashMap

Finally, the sorted elements are iterated over and added to the output container:

.forEach(eachEntry -> output.put(eachEntry.getValue().getName(), eachEntry.getValue().getSalary()));

Because `output` is a LinkedHashMap, it remembers the order in which entries were inserted, successfully preserving the sorted leaderboard ranking!

Java Implementation

Below is the complete Java code demonstrating Map value sorting using Java Streams:

package io.practise.accolite;
 
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
 
public class Example {
    public static void main(String[] args) {
        Map<Integer, TestEmployee> salaryEmployeeMap = new HashMap<>();
 
        TestEmployee te1 = new TestEmployee(500, "S1", 1);
        TestEmployee te2 = new TestEmployee(800, "S2", 2);
        TestEmployee te3 = new TestEmployee(200, "S3", 3);
        TestEmployee te4 = new TestEmployee(900, "S4", 4);
 
        salaryEmployeeMap.put(te1.getSalary(), te1);
        salaryEmployeeMap.put(te2.getSalary(), te2);
        salaryEmployeeMap.put(te3.getSalary(), te3);
        salaryEmployeeMap.put(te4.getSalary(), te4);
 
        Map<String, Integer> output = sortBasedOnValues(salaryEmployeeMap);
 
        System.out.println(output); 
        // Outputs: {S4=900, S2=800, S1=500, S3=200}
    }
 
    private static Map<String, Integer> sortBasedOnValues(Map<Integer, TestEmployee> salaryEmployeeMap) {
        LinkedHashMap<String, Integer> output = new LinkedHashMap<>();
 
        salaryEmployeeMap.entrySet().stream()
                .sorted(Map.Entry.comparingByValue((o1, o2) -> Integer.compare(o2.getSalary(), o1.getSalary())))
                .forEach(eachEntry -> output.put(eachEntry.getValue().getName(), eachEntry.getValue().getSalary()));
 
        return output;
    }
}
 
class TestEmployee {
    private int salary;
    private String name;
    private int id;
 
    public TestEmployee(int salary, String name, int id) {
        this.salary = salary;
        this.name = name;
        this.id = id;
    }
 
    public int getSalary() {
        return salary;
    }
 
    public String getName() {
        return name;
    }
 
    public int getId() {
        return id;
    }
 
    @Override
    public String toString() {
        return "TestEmployee{" +
                "salary=" + salary +
                ", name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
}

Conclusion

Standard HashMaps cannot maintain ordering. Converting Map entries into a stream and sorting them using Map.Entry.comparingByValue(), then collecting them into a LinkedHashMap is the most clean and readable way to sort Map entries by their values in Java!