Back to Stream: Sorting & Comparator
Q15Question 15 of 23

Sort employees by salary in ascending order

Key Concepts
  • sorted(Comparator.comparing(Employee::getSalary)) orders employees from lowest salary to highest
  • Comparator.comparing builds a comparator from a key extractor; ascending is the default
  • sorted() is stateful: it buffers the entire stream before ordering, unlike lazy operations like filter
  • sorted() is stable: two employees with the same salary keep their original relative order
  • The source list is never modified; sorted produces a new ordered stream
  • For BigDecimal salary, compareTo is exact with no floating-point drift

Definition

`sorted(Comparator.comparing(Employee::getSalary))` orders employees from lowest salary to highest.
  • Comparator.comparing(keyExtractor) builds a comparator that orders by the extracted key in natural ascending order.
  • sorted(comparator) is a stateful intermediate operation that buffers all elements, sorts them, and passes them downstream.
  • Stable sort: elements with equal keys retain their original relative order.
  • Non-mutating: the source list is never changed; sorted produces a new ordered stream.
  • BigDecimal: compareTo is exact with no floating-point drift, ideal for money.

The payroll manager at the National Bank of India wants the employee list arranged from the lowest salary at the top to the highest at the bottom, like lining people up shortest to tallest by pay.

Understanding the Concepts

How do you sort employees by salary ascending?

JAVA
package com.bank.hr;

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

public class SortBySalary {
    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> sorted = staff.stream()
            .sorted(Comparator.comparing(Employee::getSalary))
            .collect(Collectors.toList());

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

How is Comparator.comparing different from a manual lambda?

DIAGRAM
| Approach | Code | Readability |
|---|---|---|
| Comparator.comparing | `Comparator.comparing(Employee::getSalary)` | Clean, declarative |
| Lambda | `(a, b) -> a.getSalary().compareTo(b.getSalary())` | Verbose, error-prone |

Comparator.comparing is preferred because it is shorter, less error-prone, and chains naturally with reversed() and thenComparing().

Why is sorted() stateful?

sorted must see all elements before it can order them. Unlike filter or map, which process element by element, sorted buffers the whole stream into an internal array, sorts it, and then passes elements downstream.

What are common mistakes?

Mistake: using subtraction to compare BigDecimal values instead of compareTo.

JAVA
// WRONG: subtraction does not work for BigDecimal
// (a, b) -> a.getSalary() - b.getSalary()  // compilation error!

// WRONG: casting to int loses precision for large values
// (a, b) -> a.getSalary().subtract(b.getSalary()).intValue()

// CORRECT: use Comparator.comparing with the key extractor
Comparator.comparing(Employee::getSalary)

What about sorting with double salary?

If salary is a primitive double, use Comparator.comparingDouble to avoid boxing.

JAVA
// For double salary (not recommended for real money)
staff.stream()
    .sorted(Comparator.comparingDouble(Employee::getSalaryAsDouble))
    .collect(Collectors.toList());

Does sorted modify the original list?

No. sorted() produces a new ordered stream. The original list remains in its original order.

JAVA
List<Employee> original = new ArrayList<>(staff);
List<Employee> sorted = staff.stream()
    .sorted(Comparator.comparing(Employee::getSalary))
    .collect(Collectors.toList());

// original is unchanged
assert original.get(0).getName().equals("Rajesh");

What about stability?

Two employees with the same salary keep their original relative order because Java's sort is stable. This is useful when you later add a secondary sort key.

What should a senior engineer know?

  • For BigDecimal, Comparator.comparing delegates to BigDecimal.compareTo, which is exact.
  • Never compare money by subtracting values; it overflows and does not work for BigDecimal.
  • sorted is O(n log n) and requires O(n) extra memory for the internal buffer.
  • On parallel streams, sorted is a barrier: all elements must arrive before sorting can begin.

What are common interview follow-up questions?

  • "How do you sort descending?" Call .reversed() on the comparator.
  • "How do you add a secondary sort?" Chain .thenComparing(Employee::getName).
  • "Does sorted modify the original list?" No, it produces a new stream.

Visual Overview

DIAGRAM
  Unsorted stream
  [Rajesh/95000, Priya/120000, Amit/85000, Kavita/78000]
       │
       │  sorted(Comparator.comparing(Employee::getSalary))
       │  (buffers all, sorts ascending)
       ▼
  Sorted stream
  [Kavita/78000, Amit/85000, Rajesh/95000, Priya/120000]
       │
       │  collect(toList())
       ▼
  List<Employee> in ascending salary order

Key Takeaway

To sort a stream by a field I use sorted with a comparator built by Comparator.comparing and a key extractor. For ascending salary I pass the salary getter, and because comparing is ascending by default, the stream comes out from the lowest earner to the highest.

In my banking project at the National Bank of India this was a salary review where the payroll manager wanted the list from lowest to highest so she could scan for anomalies at the bottom of the pay scale.

sorted is stateful (buffers all elements), stable (equal salaries keep original order), and non-mutating (source list untouched). For BigDecimal the comparison is exact with no floating-point drift. Never compare money by subtraction.

Remember one sentence: sorted(Comparator.comparing(Employee::getSalary)) orders a stream by salary ascending without modifying the source list.

---

Share
Use ← → arrow keys to navigate