Explain Codes LogoExplain Codes Logo

How to use a Java8 lambda to sort a stream in reverse order?

java
lambda
stream
sorting
Anton ShumikhinbyAnton Shumikhin·Oct 9, 2024
TLDR

Getting straight to the point, we sort a stream in reverse using sorted() combined with Comparator's reversed() method.

List<String> descList = list.stream() .sorted(Comparator.reverseOrder()) .collect(Collectors.toList());

For custom types or specific fields, we make use of Comparator.comparing():

List<CustomType> descList = list.stream() .sorted(Comparator.comparing(CustomType::getField).reversed()) .collect(Collectors.toList());

To sort a list of files by lastModified dates in reverse order, do this :

List<File> sortedFiles = files.stream() .sorted(Comparator.comparing(File::lastModified).reversed()) .collect(Collectors.toList());

This ensures that the lower values are at the end of the list as reversed() flips the natural order.

From lambdas to method references

Replacing lambda expressions with method references can improve the readability of the code and make it easier to maintain:

list.stream() .sorted(Comparator.comparing(MyClass::getValue).reversed()) .forEach(System.out::println); // There are 50 ways to leave your lover, but only 1 way to sort a list in Java8 -- Paul Simon.

Here, MyClass::getValue is a method reference used to extract the values to sort on, and the reversed() method changes the sorting order.

Tweaking streams after sorting

After sorting streams, you might want to conduct more stream operations. Use Java 8 streams for efficient and readable code:

  • Filtering
list.stream() .sorted(Comparator.comparing(String::length).reversed()) .filter(s -> s.startsWith("A")) // Special treatment for lovers of the letter 'A' .collect(Collectors.toList());
  • Skipping and limiting
list.stream() .sorted(Comparator.comparingInt(String::length).reversed()) .skip(2) // The two longest strings were too long for Twitter. .limit(5) // But five copies of the "Hello, World!" string won't. .collect(Collectors.toList());
  • Deleting elements directly from a stream compromises the immutability principle of streams. Instead, retrieve the results, and then modify the collected data.

Sorting scenarios you might encounter

Dealing with complex sorting cases is fairly common. Here are some examples:

  • Nested attributes sorting:
list.stream() .sorted(Comparator.comparing((CustomType t) -> t.getNestedType().getNestedField()).reversed()) .collect(Collectors.toList());
  • Multiple fields sorting:
list.stream() .sorted(Comparator.comparing(CustomType::getPrimaryField) .thenComparing(CustomType::getSecondaryField).reversed()) .collect(Collectors.toList());
  • Handling nulls with care:
list.stream() .sorted(Comparator.comparing(CustomType::getField, Comparator.nullsLast(Comparator.naturalOrder())).reversed()) .collect(Collectors.toList());
  • Custom comparator for more complex logic:
list.stream() .sorted((o1, o2) -> { // insert complex logic here return o2.compareTo(o1); // reversed // Life is short, sort it in reverse. }) .collect(Collectors.toList());