Java Streams Comparators with Examples

Hi all, in this article, we will learn Java Streams Comparators like Comparator.comparing(), Comparator.naturalOrder(), Comparator.reverseOrder(), etc. The Comparator Interface provides us comparison and sorting options that we can use with Java Streams. Let’s start to do some examples and learn these tricks.

Java Streams Comparators with Examples

We will start with Sorting with Comparator examples then we will see Comparator.comparing() examples. 

Sorting with Comparator Natural Order and Reverse Order

Let’s start with some sorting examples. We can use the Comparator interface’s naturalOrder() and reverseOrder() method to sort the elements of a stream in Ascending and Descending order.

  • naturalOrder() equals to Ascending Order
  • reverseOrder() equals to Descending Order
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class StreamSorted {
    List<Integer> numbers = new ArrayList<>();

    @BeforeEach
    public void setup(TestInfo testInfo) {
        System.out.println("Test name: " + testInfo.getDisplayName());
        numbers.add(5);
        numbers.add(8);
        numbers.add(3);
        numbers.add(7);
        numbers.add(2);
        numbers.add(6);
        numbers.add(1);
        numbers.add(10);
        numbers.add(9);
        numbers.add(4);
    }

    @AfterEach
    public void tearDown() {
        numbers.clear();
        System.out.println("");
    }

    /**
     * Natural sort is Ascending Sort
     */
    @Test
    @Order(1)
    public void streamNaturalOrderSortTest() {
        numbers.stream()
            .peek(number -> System.out.println("Filter operation for number: " + number)) //Peek is used for debugging purposes.
            .filter(number -> number % 2 == 1) //Filter the odd numbers
            .sorted(Comparator.naturalOrder()) //Natural order of sorting. (Ascending Sort)
            .limit(4) //After 4th element stop the stream. Process first 4 element.
            .peek(number -> System.out.println("Map operation for number: " + number)) //Peek is used for debugging purposes.
            .map(number -> number * 2) //Transform the number to number*2
            .forEach(number -> System.out.println("Result of stream: " + number)); //Print the results.
    }

    /**
     * Reverse sort is Descending Sort
     */
    @Test
    @Order(2)
    public void streamReverseOrderSortTest() {
        numbers.stream()
            .peek(number -> System.out.println("Filter operation for number: " + number)) //Peek is used for debugging purposes.
            .filter(number -> number % 2 == 1) //Filter the odd numbers
            .sorted(Comparator.reverseOrder()) //Reverse order of sorting. (Descending Sort)
            .limit(4) //After 4th element stop the stream. Process first 4 element.
            .peek(number -> System.out.println("Map operation for number: " + number)) //Peek is used for debugging purposes.
            .map(number -> number * 2) //Transform the number to number*2
            .forEach(number -> System.out.println("Result of stream: " + number)); //Print the results.
    }
}

Outputs

NaturalOrder Test Output

The test code:

  • Prints the debugging texts with peek().
  • Filters the odd numbers.
  • Then, sorts all elements with Natural Order which is Ascending Order.
  • With limit(4), when the 4th odd number is filtered which is “1”, it does not continue to do operations for other elements.
  • Prints the debugging texts with peek(),
  • Transform the elements to (elements*2).
  • Prints the results with forEach().

java stream comparator example

ReverseOrder Test Output

The test code:

  • Prints the debugging texts with peek().
  • Filters the odd numbers.
  • Then, sorts all elements with Reverse Order which is Descending Order.
  • With limit(4), when the 4th odd number is filtered which is “1”, it does not continue to do operations for other elements.
  • Prints the debugging texts with peek(),
  • Transform the elements to (elements*2).
  • Prints the results with forEach().

sort with comparator in java

Java Streams Comparator.comparing() Examples

The Comparator Interface provides us several comparisons and sorting options as seen below screenshot. We have already learned the reverseOrder() and naturalOrder() sorting with the Comparator Interface.

java comparator interface

Now, let’s do some examples with Comparator.comparing(). We have a Footballer class which contains the footballer’s name, team, and age. We can do comparisons on each element of the footballers by using comparator.comparing() method. We can find the footballer who has minimum age or the footballer who has maximum age etc. 

Footballer Class

I used Lombok library’s Getter, Setter, and AllArgConstructor annotations to construct the Footballer class.

@Setter
@Getter
@AllArgsConstructor
public class Footballer {
    String name;
    String team;
    int    age;

    @Override public String toString() {
        return "Footballer{" +
            "name='" + name + '\'' +
            ", team='" + team + '\'' +
            ", age=" + age +
            '}';
    }
}

and now time to write some tests to see Comparator.comparing() in action. In our examples, we will find the youngest and eldest football players.

public class ComparatorExamples {
    List<Footballer> footballers = new ArrayList<>();

    @BeforeEach
    public void setup() {
        Footballer ronaldo = new Footballer("Ronaldo", "Manchester United", 36);
        Footballer messi = new Footballer("Messi", "Paris Saint German", 33);
        Footballer ozil = new Footballer("Ozil", "Fenerbahce", 32);
        footballers.add(ronaldo);
        footballers.add(messi);
        footballers.add(ozil);
    }

    /**
     * Comparator.comparing example
     */
    @Test
    public void comparatorComparingTest() {
        Optional<Footballer> youngestFootballer = footballers.stream()
            .min(Comparator.comparing(Footballer::getAge));

        Optional<Footballer> eldestFootballer = footballers.stream()
            .max(Comparator.comparing(Footballer::getAge));

        youngestFootballer.ifPresent(footballer -> System.out.println("Youngest Footballer: " + footballer));
        eldestFootballer.ifPresent(footballer -> System.out.println("Eldest Footballer: " + footballer));
    }
}

Output

As you see below, by using Comparator.comparing() inside Stream’s min() and max() methods, we can easily find the youngest and eldest football players. Min and max method’s return type is Optional that’s why I wrapped the Footballer class with Optional. I will explain Optional class details in another article. Simply, it will help us not to get null pointer exceptions in Java.

comparator.comparing example

GitHub Project

https://github.com/swtestacademy/java-functional/tree/main/src/test/java/functional/stream/comparator

In this article, I shared with you the most common usages of the Comparator Interface in Java. I hope you enjoyed reading it. See you in the next articles.

Thanks for reading,
Onur Baskirt

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.