Back to Collectors
Q20Question 20 of 21

Sort a Map<String, Double> by value descending and collect into LinkedHashMap

Key Concepts
  • Map.Entry.comparingByValue(Comparator.reverseOrder()) sorts entries by value descending
  • LinkedHashMap preserves insertion order, so collecting into it after sorting maintains the ranking
  • HashMap has no ordering guarantee, so sorting into a HashMap silently loses the order
  • Use the four-argument toMap with LinkedHashMap::new to preserve sorted order
  • The merge function in the four-argument toMap is a formality when keys are unique
  • This pattern is the standard way to produce a ranked leaderboard from a map

Definition

Sort entrySet by value descending, then collect into a LinkedHashMap to preserve the ranking.
  • 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) -> a is 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.

JAVA
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));
    }
}
TEXT
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 |

JAVA
// 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.

JAVA
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?

JAVA
// 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.

JAVA
// 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.

JAVA
// 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

DIAGRAM
  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.

---

Share
Use ← → arrow keys to navigate