DEV Community

DevCorner2
DevCorner2

Posted on

🔍 Mastering Sorting in Java with Comparator: A Deep Dive into Lists, Maps, Sets, Queues, and Custom Objects

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]
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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));
Enter fullscreen mode Exit fullscreen mode

📋 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
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode

🗺️ 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));
Enter fullscreen mode Exit fullscreen mode

💰 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));
Enter fullscreen mode Exit fullscreen mode

🔁 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());
Enter fullscreen mode Exit fullscreen mode

SortedSet Example (TreeSet)

SortedSet<String> treeSet = new TreeSet<>(Comparator.reverseOrder());
treeSet.addAll(List.of("Delta", "Alpha", "Bravo"));
System.out.println(treeSet); // [Delta, Bravo, Alpha]
Enter fullscreen mode Exit fullscreen mode

🪜 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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

🔧 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());
Enter fullscreen mode Exit fullscreen mode

📌 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() or Arrays.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();
Enter fullscreen mode Exit fullscreen mode

🚀 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)