Sort Objects Using Comparator in Java
Problem
A Comparator defines sorting logic from outside the class being sorted, so a class doesn't need to implement Comparable itself just to be sortable one particular way.
Given a list of Employee objects, sort them by salary using a Comparator instead of modifying the Employee class.
Java Program
import java.util.ArrayList;
import java.util.List;
class Employee {
String name;
double salary;
Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
}
public class SortObjectsUsingComparator {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("Alice", 55000.0));
employees.add(new Employee("Bob", 42000.0));
employees.add(new Employee("Charlie", 61000.0));
employees.sort((a, b) -> Double.compare(a.salary, b.salary)); // external comparison rule
for (Employee e : employees) {
System.out.println(e.name + ": " + e.salary);
}
}
}Output
Core Logic
Passing a lambda that compares two Employee objects by their salary field directly to sort() supplies the ordering rule without Employee ever needing to implement Comparable.
- 1
Employeeis a plain class withnameandsalaryfields — it implements no sorting-related interface at all. - 2
employees.sort((a, b) -> Double.compare(a.salary, b.salary))passes a lambda that compares two employees purely by salary. - 3
Double.compare()returns negative, zero, or positive depending on which salary is smaller, larger, or equal — exactly whatsort()needs to order the list. - 4The list is sorted in place; no new list is created.
[Alice(55000), Bob(42000), Charlie(61000)] by salary produces [Bob, Alice, Charlie], ascending.Key Point: Because the Comparator lives outside Employee, the exact same objects could be sorted a completely different way elsewhere — by name, for instance — just by passing a different lambda, without touching the Employee class at all.
Why: List.sort() uses a merge-based algorithm (TimSort) for object lists, which does O(n log n) comparisons and needs a temporary array of size proportional to n for merging.
Key Concepts
Approach 2: Java 8
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
class EmployeeRecord {
String name;
double salary;
EmployeeRecord(String name, double salary) {
this.name = name;
this.salary = salary;
}
}
public class SortObjectsUsingComparatorStream {
public static void main(String[] args) {
List<EmployeeRecord> employees = List.of(
new EmployeeRecord("Alice", 55000.0),
new EmployeeRecord("Bob", 42000.0),
new EmployeeRecord("Charlie", 61000.0)
);
// Sorts by the extracted salary key, collecting into a new list
List<EmployeeRecord> sorted = employees.stream()
.sorted(Comparator.comparingDouble(e -> e.salary))
.collect(Collectors.toList());
for (EmployeeRecord e : sorted) {
System.out.println(e.name + ": " + e.salary);
}
}
}
Output
Core Logic
Sorting the stream with Comparator.comparingDouble() and collecting the result expresses the same salary-based ordering as a pipeline, using a purpose-built comparator factory instead of a hand-written lambda.
- 1
employees.stream()opens a stream over the list's elements. - 2
Comparator.comparingDouble(e -> e.salary)builds a comparator from a key-extractor function, replacing the manual(a, b) -> Double.compare(a.salary, b.salary)lambda with an equivalent, more declarative expression. - 3
.sorted(...)applies that comparator to produce a new, sorted stream, leaving the original list untouched. - 4
.collect(Collectors.toList())gathers the sorted stream into a new List. - 5Unlike the primary approach's in-place
sort(), this produces a separate sorted list rather than reorderingemployeesitself.
[Alice(55000), Bob(42000), Charlie(61000)] by salary collects into [Bob, Alice, Charlie], the same ascending order the primary approach produces.Key Point: Comparator.comparingDouble() (and its comparingInt()/comparing() siblings) reads as 'sort by this key', which is often clearer than a raw comparison lambda once the sort key is just a single field.
Why: sorted() still performs the same comparison-based sort as List.sort(), and collect() additionally builds a new list to hold the result, unlike the primary approach's in-place sort.