ZetCode

Java Stream sorted

last modified May 24, 2025

This article delves into the Java Stream sorted method, a versatile tool for ordering elements within a stream. It enables developers to arrange data, such as numbers, strings, or custom objects, in a specified order, making it an essential feature for processing collections in a functional programming style.

The sorted method is an intermediate operation in the Java Stream API that produces a new stream with the elements of the original stream arranged in a defined order. As a stateful operation, it must process the entire stream to determine the correct sequence, which may impact performance for large datasets. It supports sorting in natural order for elements that implement Comparable or in a custom order defined by a provided Comparator.

Basic sorted syntax

The sorted method has two variants:

Stream<T> sorted()
Stream<T> sorted(Comparator<? super T> comparator)

The first variant, sorted, arranges elements in their natural order, requiring that the elements implement the Comparable interface, such as strings (sorted alphabetically) or numbers (sorted numerically). If the elements do not implement Comparable, a runtime exception occurs.

The second variant, sorted(Comparator), allows for custom sorting logic using a provided Comparator, enabling flexible ordering, such as reverse sorting or sorting by specific object properties. This makes it suitable for complex sorting requirements. Both variants return a new stream, leaving the original data source unchanged, and are optimized for parallel processing, though developers should be mindful of memory usage with large streams due to the stateful nature of the operation.

Natural ordering of numbers

Sorting numbers using natural order.

Main.java
void main() {

    Stream<Integer> numbers = Stream.of(5, 3, 8, 1, 2, 7, 4, 6);
    
    numbers.sorted()
          .forEach(System.out::println);
}

This example sorts integers in ascending order using their natural ordering. The sorted method without arguments relies on the elements implementing Comparable.

Reverse order sorting

Sorting elements in reverse order using Comparator.reverseOrder.

Main.java
void main() {

    Stream<String> words = Stream.of("banana", "apple", "pear", "orange");
    
    words.sorted(Comparator.reverseOrder())
         .forEach(System.out::println);
}

This example sorts strings in reverse alphabetical order. The Comparator.reverseOrder method returns a comparator that imposes the reverse of natural ordering.

$ java Main.java
pear
orange
banana
apple

Custom object sorting

In the following example, we will sort custom objects using a Comparator. This is a common scenario when dealing with collections of user-defined types, such as sorting a list of people by their age or name.

Main.java
record Person(String firstName, String lastName, String occupation) {
}

void main() {

    Stream<Person> people = Stream.of(
        new Person("John", "Doe", "Engineer"),
        new Person("Jane", "Smith", "Doctor"),
        new Person("Alice", "Johnson", "Artist"),
        new Person("Bob", "Brown", "Engineer"),
        new Person("Charlie", "Davis", "Teacher"),
        new Person("Diana", "Wilson", "Artist")

    );
    
    people.sorted(Comparator.comparing(Person::occupation))
          .forEach(p -> System.out.println(p));
}

This example sorts Person objects by their occupation using a Comparator. The comparing method creates a comparator that compares Person objects based on the specified property, which in this case is the occupation.

$ java Main.java
Person[firstName=Alice, lastName=Johnson, occupation=Artist]
Person[firstName=Diana, lastName=Wilson, occupation=Artist]
Person[firstName=Jane, lastName=Smith, occupation=Doctor]
Person[firstName=John, lastName=Doe, occupation=Engineer]
Person[firstName=Bob, lastName=Brown, occupation=Engineer]
Person[firstName=Charlie, lastName=Davis, occupation=Teacher]

This example demonstrates how to sort Person objects by their date of birth.

Main.java
record Person(String firstName, String lastName, String dob) {
    public int age() {

        return Period.between(LocalDate.parse(dob), LocalDate.now()).getYears();
    }
}

void main() {

    Stream<Person> people = Stream.of(

            new Person("John", "Doe", "1987-01-01"),
            new Person("Jane", "Smith", "1990-05-15"),
            new Person("Alice", "Johnson", "2000-03-20"),
            new Person("Bob", "Brown", "1995-07-30"),
            new Person("Charlie", "Davis", "1980-12-10"),
            new Person("Diana", "Wilson", "2002-11-25")
    );

    people.sorted(Comparator.comparing(Person::dob))
            .forEach(p -> System.out.println(p));
}

This example sorts Person objects by their date of birth (dob). The comparing method creates a comparator that compares Person objects based on the specified property, which in this case is the date of birth. The dob field is expected to be in the format yyyy-MM-dd, allowing for correct chronological sorting.

Multiple sort criteria

In the next example we sort a list of employees by multiple criteria: department, salary, and name.

Main.java
record Employee(String name, String department, double salary) {
}

void main() {

    Stream<Employee> employees = Stream.of(
        new Employee("Alice", "HR", 75000),
        new Employee("Bob", "IT", 80000),
        new Employee("Charlie", "IT", 75000),
        new Employee("Diana", "HR", 80000)
    );
    
    employees.sorted(Comparator.comparing(Employee::department)
                             .thenComparing(Employee::salary)
                             .thenComparing(Employee::name))
            .forEach(e -> System.out.println(
                e.department() + " - " + e.salary() + " - " + e.name()));
}

This example sorts employees first by department, then by salary, and finally by name. The thenComparing method allows chaining multiple comparators.

$ java Main.java
HR - 75000.0 - Alice
HR - 80000.0 - DianathenComparing
IT - 75000.0 - Charlie
IT - 80000.0 - Bob

Case-insensitive string sorting

In the next example, we will sort strings in a case-insensitive manner.

Main.java
void main() {

    Stream<String> mixedCase = Stream.of("apple", "Banana", "cherry", "Date");
    
    mixedCase.sorted(String.CASE_INSENSITIVE_ORDER)
             .forEach(System.out::println);
}

This example sorts strings ignoring case differences. The String.CASE_INSENSITIVE_ORDER comparator provides case-insensitive comparison of strings.

$ java Main.java
apple
Banana
cherry
Date

Sorting with null values

The next example demonstrates how to handle null values in sorting using Comparator.nullsFirst and Comparator.nullsLast.

Main.java
void main() {

    Stream<String> withNulls = Stream.of("banana", null, "apple", null, "cherry");
    
    System.out.println("Nulls first:");
    withNulls.sorted(Comparator.nullsFirst(Comparator.naturalOrder()))
             .forEach(System.out::println);
    
    System.out.println("\nNulls last:");
    Stream<String> withNulls2 = Stream.of("banana", null, "apple", null, "cherry");
    withNulls2.sorted(Comparator.nullsLast(Comparator.naturalOrder()))
              .forEach(System.out::println);
}

This example demonstrates handling null values in sorting. nullsFirst places nulls before non-null elements, while nullsLast places them after.

$ java Main.java
Nulls first:
null
null
apple
banana
cherry

Nulls last:
apple
banana
cherry
null
null

Source

Java Stream sorted documentation

In this article we have explored the Java Stream sorted method. It provides flexible options for ordering stream elements using natural ordering or custom comparators. Understanding sorting is essential for effective stream processing and data manipulation in Java.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Java tutorials.