Sorting is a core operation in programming—whether you're displaying ranked scores, arranging data in a report, or handling priority-based tasks. Java provides powerful tools to sort any type of data structure using Comparator
. In this blog, we’ll explore how to sort:
- Arrays
- Lists
- Maps (by keys/values)
- Sets
- Queues
- User-defined objects
We'll cover both Java 8+ Lambda style and classic anonymous classes, giving you production-ready, clean code.
🔗 Comparator vs Comparable: A Quick Refresher
-
Comparable: The object itself defines the natural order. Override
compareTo()
. - Comparator: You define custom sort logic externally. More flexible and reusable.
🔠 1. Sorting Arrays with Comparator
Sorting Primitive Array
int[] numbers = {5, 3, 9, 1};
Arrays.sort(numbers); // Ascending order
System.out.println(Arrays.toString(numbers)); // [1, 3, 5, 9]
Sorting Object Array with Comparator
String[] names = {"John", "Alice", "Bob"};
Arrays.sort(names, Comparator.reverseOrder()); // Descending
System.out.println(Arrays.toString(names)); // [John, Bob, Alice]
Custom Object Array
User[] users = {
new User("Alice", 25),
new User("Bob", 30),
new User("Charlie", 28)
};
Arrays.sort(users, Comparator.comparingInt(u -> u.age));
📋 2. Sorting Lists with Comparator
Sort List of Strings
List<String> names = Arrays.asList("Xander", "Alice", "Bob");
names.sort(String::compareTo); // Natural order
names.sort(Comparator.reverseOrder()); // Descending
Sort List of Custom Objects
class User {
String name;
int age;
// constructor, toString()
}
List<User> users = List.of(
new User("Charlie", 30),
new User("Alice", 25),
new User("Bob", 28)
);
// Sort by name
List<User> sortedByName = users.stream()
.sorted(Comparator.comparing(u -> u.name))
.collect(Collectors.toList());
// Sort by age
List<User> sortedByAge = users.stream()
.sorted(Comparator.comparingInt(u -> u.age))
.collect(Collectors.toList());
🗺️ 3. Sorting Maps by Keys and Values
🔑 Sort Map by Keys
Map<String, Integer> map = Map.of("John", 5, "Alice", 3, "Bob", 7);
Map<String, Integer> sortedByKey = map.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue,
(e1, e2) -> e1, LinkedHashMap::new));
💰 Sort Map by Values
Map<String, Integer> sortedByValue = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue,
(e1, e2) -> e1, LinkedHashMap::new));
🔁 4. Sorting Sets
Since sets (like HashSet
) are unordered, we convert them to a list before sorting.
Sort HashSet
Set<String> set = new HashSet<>(Set.of("Delta", "Alpha", "Bravo"));
List<String> sortedList = set.stream()
.sorted()
.collect(Collectors.toList());
SortedSet Example (TreeSet)
SortedSet<String> treeSet = new TreeSet<>(Comparator.reverseOrder());
treeSet.addAll(List.of("Delta", "Alpha", "Bravo"));
System.out.println(treeSet); // [Delta, Bravo, Alpha]
🪜 5. Sorting Queues with PriorityQueue
Integer Queue (Min Heap)
Queue<Integer> pq = new PriorityQueue<>(Comparator.naturalOrder());
pq.add(3); pq.add(1); pq.add(4);
while (!pq.isEmpty()) {
System.out.print(pq.poll() + " "); // 1 3 4
}
Custom Object Queue
class User {
String name;
int age;
// constructor, toString()
}
Queue<User> pq = new PriorityQueue<>(Comparator.comparingInt(u -> u.age));
pq.add(new User("Charlie", 30));
pq.add(new User("Alice", 25));
pq.add(new User("Bob", 28));
while (!pq.isEmpty()) {
System.out.println(pq.poll()); // Ascending age order
}
🔧 6. Custom Comparator Combinations
Sort by Age Then Name
Comparator<User> byAgeThenName = Comparator
.comparingInt((User u) -> u.age)
.thenComparing(u -> u.name);
List<User> sorted = users.stream()
.sorted(byAgeThenName)
.collect(Collectors.toList());
📌 Summary Table
Collection Type | Sort Method | Supports Comparator? | Notes |
---|---|---|---|
Array | Arrays.sort() |
✅ | Can sort with custom comparator |
List |
list.sort() / stream.sorted()
|
✅ | Most flexible and recommended |
Map | entrySet().stream().sorted() |
✅ | Must collect to LinkedHashMap |
Set | Convert to list / Use TreeSet
|
✅ | TreeSet maintains order |
Queue | Use PriorityQueue
|
✅ | Ideal for min/max heaps |
🧠 Best Practices
- Prefer immutable lists + stream sorting in Java 8+ for safety.
- Always use LinkedHashMap if you want to preserve the order after sorting a map.
- Use Comparator chaining (
thenComparing
) for multi-level sort. - For performance-sensitive code, stick with
Collections.sort()
orArrays.sort()
.
📚 Bonus: Common Comparator Patterns
// Nulls first
Comparator.nullsFirst(Comparator.naturalOrder());
// Case-insensitive string sort
Comparator.comparing(String::toLowerCase);
// Reversed sort
Comparator.comparingInt(User::getAge).reversed();
🚀 Wrapping Up
Sorting in Java is more powerful and expressive than ever thanks to Comparator
, lambda expressions, and streams. Whether you're sorting simple arrays or complex objects in maps and queues, this guide gives you everything you need to do it right—cleanly, efficiently, and idiomatically.
Top comments (0)