Definition
- entrySet().stream().sorted(comparingByValue(reverseOrder())) orders entries by value descending.
- LinkedHashMap preserves insertion order, so the sorted order survives.
- HashMap has no ordering, so sorting into it loses the rank.
- Use the four-argument toMap with a LinkedHashMap supplier.
- The merge function
(a, b) -> ais a formality since source keys are unique.
Priya at the National Bank of India has a name-to-salary list in no order. She wants it ranked highest paid first and kept in that ranking. She sorts the lines by amount descending and writes them into an ordered ledger that remembers the sequence.
Understanding the Concepts
How do you sort a map by value descending?
Stream the entrySet, sort by value in reverse order, and collect into a LinkedHashMap to preserve the sorted insertion order.
package com.bank.hr;
import java.util.*;
import java.util.stream.Collectors;
public class SortMapByValue {
public static void main(String[] args) {
Map<String, Double> salaries = Map.of(
"Rajesh", 75000.0,
"Priya", 82000.0,
"Amit", 68000.0,
"Kavita", 91000.0,
"Neha", 78000.0
);
Map<String, Double> ranked = salaries.entrySet().stream()
.sorted(Map.Entry.<String, Double>comparingByValue(
Comparator.reverseOrder()))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(a, b) -> a,
LinkedHashMap::new));
ranked.forEach((name, salary) ->
System.out.printf("%-8s %.0f%n", name, salary));
}
}
Kavita 91000
Priya 82000
Neha 78000
Rajesh 75000
Amit 68000
Why is LinkedHashMap required?
A HashMap does not guarantee any iteration order. If you collect sorted entries into a HashMap, the order is lost.
| Map type | Preserves insertion order? | Use case |
|---|---|---|
| HashMap | No | Unordered lookups |
| LinkedHashMap | Yes | Maintaining sorted/insertion order |
| TreeMap | No (sorts by key) | Key-sorted maps |
// WRONG: HashMap loses the sorted order
Map<String, Double> unsorted = salaries.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue));
// Iteration order is unpredictable!
// CORRECT: LinkedHashMap preserves sorted order
Map<String, Double> sorted = salaries.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue,
(a, b) -> a, LinkedHashMap::new));
How do you sort by value ascending?
Remove the Comparator.reverseOrder() argument.
Map<String, Double> ascending = salaries.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue,
(a, b) -> a, LinkedHashMap::new));
How do you sort by key instead of value?
// Sort by name (key) alphabetically
Map<String, Double> byName = salaries.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue,
(a, b) -> a, LinkedHashMap::new));
// Or simply use TreeMap for key-sorted maps
Map<String, Double> treeMap = new TreeMap<>(salaries);
What are common mistakes?
Mistake 1: sorting into a HashMap and expecting the order to stick.
// This code looks correct but the output is shuffled
Map<String, Double> wrong = salaries.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue));
// HashMap loses the sort order!
Mistake 2: type inference issues with comparingByValue.
// This may not compile due to type inference:
sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
// Fix: add explicit type parameters
sorted(Map.Entry.<String, Double>comparingByValue(
Comparator.reverseOrder()))
What should a senior engineer know?
- Sorting into a HashMap and expecting order is a classic silent bug. The code compiles and runs but the output is shuffled.
- The merge function in the four-argument toMap is needed only for duplicate keys. Since source map keys are unique, it is never called. Use (a, b) -> a as a safe placeholder.
- For very large maps, consider whether the full sort is necessary. If you only need the top N, use sorted().limit(N) before collecting.
- LinkedHashMap iteration order is insertion order, which after sorted collection equals the sort order.
What are common interview follow-up questions?
- "How do you get the top 3 highest-paid?" Add .limit(3) after sorted().
- "How do you sort by value then by key for ties?" Chain comparators: comparingByValue().thenComparing(comparingByKey()).
- "Is there a way to keep a map permanently sorted by value?" No built-in map does this. TreeMap sorts by key only.
Visual Overview
Map<String, Double> (unordered HashMap)
{Rajesh=75K, Priya=82K, Amit=68K, Kavita=91K, Neha=78K}
│
│ entrySet().stream()
│ .sorted(comparingByValue(reverseOrder()))
▼
Sorted stream of entries:
Kavita=91K, Priya=82K, Neha=78K, Rajesh=75K, Amit=68K
│
│ toMap(..., LinkedHashMap::new)
▼
LinkedHashMap (preserves insertion order)
┌────────────────────────┐
│ Kavita → 91000.0 │ ← highest
│ Priya → 82000.0 │
│ Neha → 78000.0 │
│ Rajesh → 75000.0 │
│ Amit → 68000.0 │ ← lowest
└────────────────────────┘
Key Takeaway
To rank a name-to-salary map from highest to lowest, stream the entrySet, sort with Map.Entry.comparingByValue(reverseOrder()), and collect into a LinkedHashMap. LinkedHashMap preserves insertion order, so since you insert in sorted order, iteration later walks the entries from highest to lowest.
The classic mistake is sorting into a HashMap and expecting the order to stick. The code looks correct but the output comes out shuffled because HashMap has no ordering guarantee. Whenever order must survive a collect, the terminal map must be order-preserving.
At the National Bank of India, the salary leaderboard used this exact pattern to display employees ranked by pay. The merge function in the four-argument toMap is a formality since keys are unique.
Remember one sentence: sort entrySet by value descending and collect into LinkedHashMap to produce a ranked map, because HashMap loses the sort order.
---