Back to Stream: Sorting & Comparator
Q16Question 16 of 23

Sort employees by salary in descending order

Key Concepts
  • Comparator.comparing(Employee::getSalary).reversed() flips ascending to descending order
  • reversed() returns a new comparator that inverts every comparison result
  • When chaining with thenComparing, reversed() applies only to the key it is called on, not the tie-breaker
  • Alternatively use Comparator.comparing(key, Comparator.reverseOrder()) to reverse a single key
  • The source list is unchanged; sorted produces a new ordered stream
  • Be precise about where reversed() binds when composing multi-key comparators

Definition

`Comparator.comparing(Employee::getSalary).reversed()` orders employees from highest salary to lowest.
  • .reversed() flips any comparator's ordering, turning ascending into descending.
  • Scope of reversal: comparing(salary).reversed() reverses only the salary; a subsequent thenComparing(name) stays ascending.
  • Alternative: Comparator.comparing(key, Comparator.reverseOrder()) reverses a single key inline.
  • Non-mutating: sorted produces a new stream; the source list is never changed.
  • Stability: reversed sorts are still stable; equal salaries keep their original relative order.

The payroll manager at the National Bank of India now wants the opposite order: the highest earners at the top, like lining people up tallest to shortest. Take the same salary comparator and flip it with reversed().

Understanding the Concepts

How do you sort descending by salary?

JAVA
package com.bank.hr;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

public class SortDescending {
    public static void main(String[] args) {
        List<Employee> staff = List.of(
            new Employee("Rajesh",  "Loans",   new BigDecimal("95000")),
            new Employee("Priya",   "IT",      new BigDecimal("120000")),
            new Employee("Amit",    "Finance", new BigDecimal("85000")),
            new Employee("Kavita",  "Loans",   new BigDecimal("78000")));

        List<Employee> descending = staff.stream()
            .sorted(Comparator.comparing(Employee::getSalary).reversed())
            .collect(Collectors.toList());

        descending.forEach(e -> System.out.printf("%s - Rs. %s%n",
            e.getName(), e.getSalary().toPlainString()));
    }
}
TEXT
Priya - Rs. 120000
Rajesh - Rs. 95000
Amit - Rs. 85000
Kavita - Rs. 78000

Where does reversed() bind in a chain?

This is a frequent source of subtle bugs. Be deliberate about where reversed binds.

| Expression | Salary order | Name tie-breaker order |
|---|---|---|
| comparing(salary).reversed().thenComparing(name) | Descending | Ascending |
| comparing(salary).thenComparing(name).reversed() | Descending | Also descending (both flipped!) |

JAVA
// CORRECT: reverse only salary, keep name ascending
Comparator<Employee> correct = Comparator
    .comparing(Employee::getSalary).reversed()
    .thenComparing(Employee::getName);

// WRONG: reverses the whole chain, including the name
Comparator<Employee> wrong = Comparator
    .comparing(Employee::getSalary)
    .thenComparing(Employee::getName)
    .reversed();  // both salary AND name are now reversed!

What are common mistakes?

Mistake: reversing the entire composed comparator instead of just the primary key.

JAVA
// WRONG: this reverses both salary and name
staff.stream()
    .sorted(Comparator.comparing(Employee::getSalary)
        .thenComparing(Employee::getName)
        .reversed())  // flips everything!
    .collect(Collectors.toList());

// CORRECT: reverse only the salary
staff.stream()
    .sorted(Comparator.comparing(Employee::getSalary).reversed()
        .thenComparing(Employee::getName))
    .collect(Collectors.toList());

What is the alternative reverseOrder approach?

JAVA
// Using Comparator.reverseOrder() as the key comparator
Comparator<Employee> alt = Comparator.comparing(
    Employee::getSalary, Comparator.reverseOrder());

This is equivalent to comparing(salary).reversed() but some developers find it clearer because the reversal is stated inline.

What about using Comparator.reversed with thenComparing?

JAVA
// Highest salary first; among equal salaries, alphabetical name
List<Employee> result = staff.stream()
    .sorted(Comparator.comparing(Employee::getSalary, Comparator.reverseOrder())
        .thenComparing(Employee::getName))
    .collect(Collectors.toList());

What should a senior engineer know?

  • reversed() is a decorator: it wraps the original comparator and negates its result.
  • The sort remains stable after reversal; equal elements keep their relative order.
  • The source list is never mutated.
  • Precision about where reversed() binds is what separates correct multi-key sorts from subtly broken ones.

What are common interview follow-up questions?

  • "What does reversed do internally?" It wraps the comparator and negates the comparison result.
  • "Does reversed affect thenComparing?" Only if reversed is called after the whole chain.
  • "Is the reversed sort still stable?" Yes.

Visual Overview

DIAGRAM
  Unsorted: [Rajesh/95000, Priya/120000, Amit/85000, Kavita/78000]
       │
       │  sorted(comparing(salary).reversed())
       ▼
  Sorted descending: [Priya/120000, Rajesh/95000, Amit/85000, Kavita/78000]

  reversed() binding:
  comparing(salary).reversed().thenComparing(name)
       │                  │              │
       │    salary DESC    │   name ASC   │
       └──────────────────┴──────────────┘

Key Takeaway

To sort descending I build the ascending comparator with Comparator.comparing and call .reversed(), which returns a new comparator that negates every comparison result so the highest salary comes first.

The critical detail is where reversed() binds in a chain. If I write comparing(salary).reversed().thenComparing(name), reversed applies only to salary and the name tie-breaker stays ascending. If instead I reversed the whole composed comparator, the name would flip too, which is a subtle and common bug.

In my banking project at the National Bank of India this was a top-earners view for a compensation audit. The sort is still stable, non-mutating, and for BigDecimal the comparison is exact.

Remember one sentence: comparing(salary).reversed() gives descending salary, and the position of .reversed() in a chain determines exactly which keys are flipped.

---

Share
Use ← → arrow keys to navigate