Java Sorting Patterns

Sorting techniques in Java

Practical Java sorting examples using streams, comparators, Collections.sort, PriorityQueue for top N, and Map.Entry sorting.

SortingComparatorStreamsPriorityQueueJava

What This Page Is About

No, this page is not about sorting algorithms like Bubble Sort, Merge Sort, Quick Sort, or Timsort. Rather, we show practical approaches to sorting in a variety of Java scenarios.

In real backend work and interviews, you often need to sort arrays, lists, records, objects, map entries, or keep only the top N items. The important skill is knowing which Java tool fits the situation.

1. Sort an Array of Numbers Using Arrays.stream

If you have a primitive int array, you can stream it, sort it, and collect it back into an array.

java
import java.util.Arrays;

public class SortNumbersArray {
    public static void main(String[] args) {
        int[] nums = {5, 2, 9, 1, 3};

        int[] sorted = Arrays.stream(nums)
                .sorted()
                .toArray();

        System.out.println(Arrays.toString(sorted));
    }
}

Output:

java
[1, 2, 3, 5, 9]

2. Sort an Array of Objects Using Arrays.stream

Here we use a Java record with two fields. The array contains products, and we sort by price.

java
import java.util.Arrays;
import java.util.Comparator;

public class SortObjectArray {
    record Product(String name, int price) {}

    public static void main(String[] args) {
        Product[] products = {
                new Product("Keyboard", 75),
                new Product("Monitor", 250),
                new Product("Mouse", 40)
        };

        Product[] sortedByPrice = Arrays.stream(products)
                .sorted(Comparator.comparingInt(Product::price))
                .toArray(Product[]::new);

        System.out.println(Arrays.toString(sortedByPrice));
    }
}

The key idea is that objects need a rule for comparison. Here the rule is: compare products by their price field.

3. Sort a List of Objects by Streaming the List

If you have a List, you can stream it, sort it, and collect the result into a new list. This keeps the original list unchanged.

java
import java.util.Comparator;
import java.util.List;

public class SortListWithStream {
    record Employee(String name, int salary) {}

    public static void main(String[] args) {
        List<Employee> employees = List.of(
                new Employee("Asha", 120_000),
                new Employee("Ben", 95_000),
                new Employee("Carlos", 140_000)
        );

        List<Employee> sortedBySalary = employees.stream()
                .sorted(Comparator.comparingInt(Employee::salary))
                .toList();

        System.out.println(sortedBySalary);
    }
}

This is useful when you want a sorted copy instead of changing the original collection.

4. Sort a List In-Place Using Collections.sort

If the list is mutable and you want to sort the actual list, use Collections.sort or list.sort.

java
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SortListInPlace {
    record Employee(String name, int salary) {}

    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>(List.of(
                new Employee("Asha", 120_000),
                new Employee("Ben", 95_000),
                new Employee("Carlos", 140_000)
        ));

        Collections.sort(
                employees,
                Comparator.comparingInt(Employee::salary)
        );

        System.out.println(employees);
    }
}

The important distinction: streaming creates a sorted result; Collections.sort changes the list itself.

5. Top N Using PriorityQueue

This is one of the most useful patterns. If you only need the top N items, you do not need to fully sort everything.

This is a partial sort. The heap keeps only the top N elements in memory at a time, instead of sorting the entire input.

Example: find the top 3 employees by salary.

java
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

public class TopNWithPriorityQueue {
    record Employee(String name, int salary) {}

    public static void main(String[] args) {
        List<Employee> employees = List.of(
                new Employee("Asha", 120_000),
                new Employee("Ben", 95_000),
                new Employee("Carlos", 140_000),
                new Employee("Dina", 110_000),
                new Employee("Evan", 160_000)
        );

        int n = 3;

        PriorityQueue<Employee> minHeap = new PriorityQueue<>(
                Comparator.comparingInt(Employee::salary)
        );

        for (Employee employee : employees) {
            minHeap.offer(employee);

            // restrict the heap to contain at most n elements
            if (minHeap.size() > n) {
                minHeap.poll();
            }
        }

        List<Employee> topN = new ArrayList<>(minHeap);

        topN.sort(
                Comparator.comparingInt(Employee::salary).reversed()
        );

        System.out.println(topN);
    }
}

The heap keeps the smallest salary among the current top N at the top. When the heap grows beyond N, we remove that smallest item.

At the end, the heap contains only the top N employees. We sort those N items only for display.

6. Sort a Map by Value Using Map.Entry::getValue

Maps are not normally “sorted by value” directly. The common pattern is to stream the entry set, sort the entries, and collect or print the result.

java
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class SortMapByValue {
    public static void main(String[] args) {
        Map<String, Integer> scores = Map.of(
                "Asha", 90,
                "Ben", 75,
                "Carlos", 95,
                "Dina", 85
        );

        Map<String, Integer> sortedByScore = scores.entrySet()
                .stream()
                .sorted(Map.Entry.comparingByValue())
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue,
                        LinkedHashMap::new
                ));

        System.out.println(sortedByScore);
    }
}

Output:

java
{Ben=75, Dina=85, Asha=90, Carlos=95}

LinkedHashMap is used so the insertion order of the sorted stream is preserved in the final map.

7. Sort a Map by Value Descending

For descending order, reverse the value comparator.

java
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class SortMapByValueDescending {
    public static void main(String[] args) {
        Map<String, Integer> scores = Map.of(
                "Asha", 90,
                "Ben", 75,
                "Carlos", 95,
                "Dina", 85
        );

        Map<String, Integer> sortedByScoreDesc = scores.entrySet()
                .stream()
                // The explicit generic types are sometimes used to help
                // Java infer the comparator's type before calling reversed().
                // In many cases they are not required, but they can make
                // the compiler's type inference unambiguous.
                .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue,
                        LinkedHashMap::new
                ));

        System.out.println(sortedByScoreDesc);
    }
}

The explicit generic type on Map.Entry can help Java understand the type before calling reversed().

8. Sort Only Part of an Array

Sometimes you do not want to sort the entire array. Java allows you to sort only a specific range.

Sorting a subrange comes up more often than people think:

  • sort only page 2 of results
  • sort only the active portion of an array
  • sort only a window in an algorithm
  • sort a partially filled buffer
java
import java.util.Arrays;

public class SortSubrange {
    public static void main(String[] args) {
        int[] nums = {9, 4, 8, 2, 7, 1, 6};

        Arrays.sort(nums, 1, 5);

        System.out.println(Arrays.toString(nums));
    }
}

Output:

java
[9, 2, 4, 7, 8, 1, 6]

The range is:

java
Arrays.sort(array, fromIndex, toIndex);

where:

  • fromIndex is inclusive
  • toIndex is exclusive

So:

java
Arrays.sort(nums, 1, 5);

sorts indices:

java
1, 2, 3, 4

while leaving the rest of the array unchanged.

Remember: the end index is exclusive. This follows the same convention used throughout much of the Java Collections and Stream APIs.

9. Sort Only Part of a List Using subList

Arrays have built-in range sorting support. Lists achieve something similar using subList().

A useful thing to know is that subList() returns a view into the original list, not a copy.

java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class SortSubList {
    public static void main(String[] args) {
        List<Integer> nums =
                new ArrayList<>(List.of(
                        9, 4, 8, 2, 7, 1, 6
                ));

        Collections.sort(nums.subList(1, 5));

        System.out.println(nums);
    }
}

Output:

java
[9, 2, 4, 7, 8, 1, 6]

The call:

java
nums.subList(1, 5)

represents the elements at indices:

java
1, 2, 3, 4

Just like Arrays.sort(...), the start index is inclusive and the end index is exclusive.

A common misconception is that subList() creates a new list. It does not. It returns a view backed by the original list, so sorting the subList directly modifies the original list.

How to Think About These Choices

Need a sorted copy?

Use stream().sorted().toList() or Arrays.stream(...).sorted().toArray().

Need to mutate the list?

Use Collections.sort(list, comparator) or list.sort(comparator).

Need only top N?

Use a PriorityQueue. Do not sort everything if you only need a small subset.

Need to sort a map?

Stream the entrySet, sort entries, then collect into LinkedHashMap if order matters.

Common Interview Follow-Ups

Does stream().sorted() modify the original list?

No. It returns a sorted stream. If you collect the result into a list, that is a new sorted list.

When should I use PriorityQueue instead of sorting?

Use PriorityQueue when you only need the top N or bottom N elements. Sorting everything costs more work than maintaining a small heap.

Why use Comparator.comparingInt instead of Comparator.comparing?

comparingInt avoids boxing int values into Integer objects, so it is usually the cleaner choice for primitive int fields.

Why use LinkedHashMap when sorting a map by value?

Because normal HashMap does not preserve insertion order. LinkedHashMap preserves the order produced by the sorted stream.

Final Takeaway

Sorting in Java is less about memorizing algorithms and more about choosing the right API for the situation: streams for sorted copies, Collections.sort for in-place sorting, comparators for custom ordering, PriorityQueue for top N, and Map.Entry helpers for sorting maps.