Hook: Interviewers love this one because it checks whether you can turn a plain-English request into a safe Java comparator without creating money bugs.
Question: How do I sort a list of Employee objects by salary in Java?
Answer: Create a Comparator that compares the salary field, then pass it to List.sort(...) or Collections.sort(...). If salary is real money, prefer BigDecimal instead of double so you avoid floating-point rounding errors. If two salaries are equal, add a tie-breaker such as name so the result is predictable.
Interview-Ready Answer: I would sort the employees with a comparator on salary. In Java, I prefer List.sort(Comparator), and for money values I use BigDecimal rather than double. If salaries can match, I add a second rule like name as a tie-breaker, and because Java’s object sort is stable, equal items keep their original order unless I define more rules.
Sorting employees by salary is not about moving objects around by hand. You are teaching Java one simple rule: when it compares two employees, which one should come first?
BigDecimal is the safest choice for money because it avoids floating-point rounding mistakes.Comparator. A comparator is a small object that says before, same, or after when it looks at two employees.null, or if salary can be null, use Comparator.nullsLast(...) or nullsFirst(...).thenComparing. This is useful when two employees have the same salary and you still want a deterministic order.employees.sort(comparator). This sorts the list in place, meaning the original list is changed.Java does not need your salary field to be the first field in the class or to implement special interfaces manually. It just needs a rule that can compare two values consistently. For object sorting, Java uses a stable algorithm called TimSort. Stable means if two items compare as equal, their original order stays the same. That matters when employees have the same salary and you do not want the display order to jump around between runs.
| Method | Mutates? | Best for | Note |
|---|---|---|---|
List.sort | Yes | Modern code | Simple and readable |
Collections.sort | Yes | Legacy code | Still fine, just older style |
Stream.sorted | No | Need a new list | Returns a sorted stream, then collect it |
For object sorting, expect about O(n log n) time in the general case. On a list of 1,000,000 employees, that means roughly 20 million compare steps in the rough mental model. Extra memory can go up to O(n) because Java may need temporary storage while sorting object data. If the list is already partly sorted, TimSort can do even better in practice.
Two important gotchas:
a - b. That can overflow for large numbers, and it is wrong for money stored as decimal values.100000 before 9000 because it compares characters, not numeric value.Use salary sorting in dashboards, payroll exports, compensation review screens, and reporting jobs. If the list is only for display, Stream.sorted() is nice because it returns a new sequence. If you need to update the same list object already held in memory, List.sort() is the cleanest choice.
Memory rule: think of the comparator as the referee. It never moves the players; it only decides who stands in front, who stands behind, and who is a tie.
Real-World Story: In a payroll or HR compensation dashboard, managers often sort employees by salary descending to find the highest-paid people quickly. The backend usually sends a list to the UI, and the UI may let users switch between ascending and descending views. If the sort logic is wrong, the whole screen can look trustworthy while quietly showing the wrong ranking.
Here is a common incident: a team stored salary as a decimal number but wrote a comparator using subtraction and then cast the result to int. For very close salaries, the comparison returned 0, so different employees appeared in random order. Managers complained that the top-10 list changed after every refresh, audit exports did not match the dashboard, and support tickets mentioned salary order is unstable
. The fix was to use a proper comparator, keep salary as BigDecimal, and add a tie-breaker so equal salaries always sort the same way.
What users would notice:
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class SortEmployeesBySalary {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("Ava", new BigDecimal("95000.00")));
employees.add(new Employee("Noah", new BigDecimal("120000.00")));
employees.add(new Employee("Mia", new BigDecimal("95000.00"))); // same salary as Ava
employees.add(new Employee("Zoe", null)); // missing salary edge case
employees.add(null); // dirty data edge case
// BigDecimal avoids floating-point rounding bugs that can break salary order.
// The tie-breaker keeps the result deterministic when salaries match.
Comparator<Employee> bySalaryAscending = Comparator.nullsLast(
Comparator.comparing(
Employee::getSalary,
Comparator.nullsLast(Comparator.naturalOrder())
).thenComparing(
Employee::getName,
Comparator.nullsLast(String.CASE_INSENSITIVE_ORDER)
)
);
Comparator<Employee> bySalaryDescending = Comparator.nullsLast(
Comparator.comparing(
Employee::getSalary,
Comparator.nullsLast(Comparator.reverseOrder())
).thenComparing(
Employee::getName,
Comparator.nullsLast(String.CASE_INSENSITIVE_ORDER)
)
);
System.out.println("Ascending by salary:");
employees.sort(bySalaryAscending);
printEmployees(employees);
System.out.println("\nDescending by salary:");
employees.sort(bySalaryDescending);
printEmployees(employees);
}
private static void printEmployees(List<Employee> employees) {
for (Employee employee : employees) {
if (employee == null) {
System.out.println("null employee");
} else {
System.out.println(employee);
}
}
}
static class Employee {
private final String name;
private final BigDecimal salary;
Employee(String name, BigDecimal salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public BigDecimal getSalary() {
return salary;
}
@Override
public String toString() {
return name + " -> " + (salary == null ? "null" : salary.toPlainString());
}
}
}Follow-up & Tricky Questions:
Comparator.reverseOrder() for comparable values or reversed() on a comparator. For money, I prefer building the descending rule directly so null handling and tie-breakers stay clear.thenComparing, such as salary first and name second. That makes the order deterministic instead of depending on the original list order alone.Comparator.nullsLast(...) or nullsFirst(...). That prevents NullPointerException and gives you an explicit business rule.List.sort sorts the same list object in place. If you want a new sorted list, use stream().sorted(...) and collect the result.BigDecimal better than double for salary? BigDecimal stores decimal values exactly enough for money calculations, while double can introduce tiny binary rounding errors that break comparisons and totals.a.salary - b.salary? That is unsafe for large numbers and incorrect for decimal money. The comparator contract also expects clean comparison logic, not arithmetic subtraction.0 for different employees? Java treats them as equal for ordering, so a stable sort keeps their original order. If that is not what you want, add a tie-breaker field.Tricky / Gotcha Questions:
BigDecimal first. String sorting compares text, not numeric size, so the order can be wrong.Collections.sort better than List.sort? Not really; both sort in place. List.sort is the modern instance method and usually reads better in new code.reversed() always preserve null handling exactly the way I want? No, reversing a whole comparator can also reverse the placement of nulls. If null behavior matters, build the descending comparator explicitly instead of relying on a blanket reverse.Common Mistakes:
Comparator.comparing(...), Integer.compare, Long.compare, or BigDecimal comparison methods.double without thinking. Correction: prefer BigDecimal for currency so pennies do not disappear into rounding errors.thenComparing with name or id.nullsFirst or nullsLast.Memory Hook: Think of salary sorting like a race scoreboard: salary is the finish time, and name is the photo-finish backup when two people cross together.
Cheat Sheet:
Comparator on salary.BigDecimal, not double.List.sort to sort in place.thenComparing for stable, deterministic ties.nullsLast or nullsFirst if data can be missing.O(n log n); object sort is stable.Practice Tasks:
null employee and a null salary, then keep the sort from failing.