Sorting Custom Objects in Java
š¹ Sorting Custom Objects (Deep Dive, Interview-Ready)
In technical interviews, you will frequently be asked to sort a collection of custom objects (like Customer, Employee, or Transaction) by a specific field. While this used to require verbose anonymous inner classes, modern Java (Java 8+) has turned this into an elegant one-liner using method references and lambdas.
š 1. The Scenario
Imagine we have a Customer class:
public class Customer { private String firstName; private String lastName; private int age; // constructor, getters, setters }
We have an ArrayList<Customer> customers. Our goal: Sort them by firstName.
š 2. Modern Java (The "Gold Standard")
If you are asked this in an interview today, you should immediately write the Java 8+ Comparator.comparing approach. It is the cleanest, most idiomatic way to sort in modern Java.
šø Using Comparator.comparing (Method Reference)
This is highly preferred because it's instantly readable.
customers.sort(Comparator.comparing(Customer::getFirstName));
šø Using a Lambda Expression
If you need slightly more custom logic during the comparison, a lambda works perfectly.
customers.sort((c1, c2) -> c1.getFirstName().compareTo(c2.getFirstName()));
š 3. Advanced Sorting (Chaining Comparators)
Interviewers often add a twist: "What if two customers have the same first name? Sort them by last name as a fallback."
With Java 8+, you don't need complex if/else logic. You can just chain Comparators using .thenComparing().
customers.sort( Comparator.comparing(Customer::getFirstName) .thenComparing(Customer::getLastName) );
šø Sorting Primitives (Avoiding Autoboxing)
If the twist is to sort by age (an int), you should avoid the performance penalty of autoboxing (converting int to Integer). Use .comparingInt():
// Sorts by first name, then by age (using primitive comparison for speed) customers.sort( Comparator.comparing(Customer::getFirstName) .thenComparingInt(Customer::getAge) );
šø Reverse Sorting (Descending Order)
Need it in descending order? Just chain .reversed().
customers.sort(Comparator.comparing(Customer::getFirstName).reversed());
š 4. The Legacy Approach (Pre-Java 8)
You should know this just in case you are working on a very old codebase, but always tell the interviewer you prefer the Java 8 approach.
Collections.sort(customers, new Comparator<Customer>() { @Override public int compare(Customer c1, Customer c2) { return c1.getFirstName().compareTo(c2.getFirstName()); } });
š Why it's bad: It requires 6 lines of boilerplate code to achieve what Java 8 does in 1 line. It clutters the codebase and reduces readability.
š 5. Sorting via Streams (Creating a new List)
If you don't want to mutate the original customers list, but instead want to create a brand new sorted list, use the Stream API.
List<Customer> sortedCustomers = customers.stream() .sorted(Comparator.comparing(Customer::getFirstName)) .collect(Collectors.toList()); // or .toList() in Java 16+
š„ Interview Gold Statement
"To sort custom objects in modern Java, I always use the
List.sort()method combined withComparator.comparing(). It allows for elegant, highly readable one-liners using method references likeCustomer::getFirstName. Furthermore, it makes complex multi-level sorting trivial by chaining.thenComparing()or.reversed(), completely eliminating the verbose anonymous inner classes required in older versions of Java."
ā” Final Verdict
- ā
Use
List.sort(Comparator.comparing(...))for all in-place sorting. - ā
Use
stream().sorted(...)when you need a new sorted copy without modifying the original array. - ā Avoid
Collections.sort()with anonymous classes unless strictly required by a legacy Java 7 compiler.