Learn to sort streams of numbers, strings and custom types in ascending (natural order) and descending orders (reverse order) in Java.
1. Basics of Sorting the Streams
The Stream interface provides the sorted() method that returns a stream consisting of the elements of a given stream, sorted according to the natural order. It is an overloaded method:
Stream sorted()
: sorted according to natural order.Stream sorted(comparator)
: sorted according to the provided Comparator.
Note that both methods are intermediate operations so we still need to call a terminal operation to trigger the sorting.
Stream<Person> unsortedStream;
//Default Ordering
List<Person> sortedList = unsortedStream.sorted()
.collect(Collectors.toList());
//Order by First Name
List<Person> sortedList = unsortedStream.sorted(Person::firstName)
.collect(Collectors.toList());
2. Sorting Custom Types
For demonstration purposes, we are using the custom class Person
. This class has only three fields: id, first name and last name.
By default, two persons are considered equal if their id
is equal.
import java.util.Objects;
public class Person implements Comparable<Person> {
private Integer id;
private String fname;
private String lname;
//Constructor, Setters and Getters are hidden for brevity
@Override
public int compareTo(Person p) {
return this.getId().compareTo(p.getId());
}
}
2.1. Default Sorting
By default, the sorted() method uses the Comparable.compareTo() method implemented by the Person
class.
As Person class compares the instances using the value of id field, so when we sort the stream of Person instances – we get the instances sorted by id. The default sorting is in the natural order.
Stream<Person> personStream = getPersonStream();
// Ascending Order
personStream.sorted()
.forEach(System.out::println);
Person [id=1, fname=Lokesh, lname=Gupta]
Person [id=2, fname=Lokesh, lname=Gupta]
Person [id=3, fname=Brian, lname=Clooney]
Person [id=4, fname=Brian, lname=Clooney]
Person [id=5, fname=Lokesh, lname=Gupta]
The same is true for reverse sorting as well. we can sort the Person instances in reverse order by passing the reverse comparator obtained from Comparator.reverseOrder() method into the sorted() method.
Stream<Person> personStream = getPersonStream();
// Reverse Order
personStream.sorted(Comparator.reverseOrder())
.forEach(System.out::println);
Person [id=6, fname=Alex, lname=Kolen]
Person [id=5, fname=Lokesh, lname=Gupta]
Person [id=4, fname=Brian, lname=Clooney]
Person [id=3, fname=Brian, lname=Clooney]
Person [id=2, fname=Lokesh, lname=Gupta]
Person [id=1, fname=Lokesh, lname=Gupta]
2.2. Custom Sorting
What if we want to sort the Person instances by their first name. The default sort does not support it, so we need to create our custom comparator.
import java.util.Comparator;
import com.howtodoinjava.core.streams.Person;
public class FirstNameSorter implements Comparator<Person>{
@Override
public int compare(Person p1, Person p2) {
if(p1.getFname() == null || p2.getFname() == null) {
throw new IllegalArgumentException("Unnamed Person found in the system");
}
return p1.getFname().compareToIgnoreCase(p2.getFname());
}
}
Now pass the FirstNameSorter instance to the sorted() method. This time, sorting will use the compare() method written in FirstNameSorter.
List<Person> sortedList = personStream.sorted(new FirstNameSorter())
.collect(Collectors.toList());
sortedList.forEach(System.out::println);
Person [id=6, fname=Alex, lname=Kolen]
Person [id=4, fname=Brian, lname=Clooney]
Person [id=3, fname=Brian, lname=Clooney]
Person [id=1, fname=Lokesh, lname=Gupta]
Person [id=5, fname=Lokesh, lname=Gupta]
Person [id=2, fname=Lokesh, lname=Gupta]
Similarly, to sort the instances by the first name in reverse order, we can reverse any comparator using its reverse() method.
List<Person> reverseSortedList = personStream.sorted( new FirstNameSorter().reversed() )
.collect(Collectors.toList());
reverseSortedList.forEach(System.out::println);
2.3. Class cannot be cast to class java.lang.Comparable
Please note that if our custom class Person does not implement the Comparable interface then we will get the ClassCastException
in runtime while doing the natural sorting.
Exception in thread "main" java.lang.ClassCastException: class com.howtodoinjava.core.streams.sort.Person
cannot be cast to class java.lang.Comparable (com.howtodoinjava.core.streams.sort.Person is in unnamed
module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
at java.base/java.util.Comparators $NaturalOrderComparator.compare(Comparators.java:47)
at java.base/java.util.TimSort. countRunAndMakeAscending(TimSort.java:355)
at java.base/java.util.TimSort. sort(TimSort.java:220)
at java.base/java.util.Arrays. sort(Arrays.java:1307)
3. Sorting Stream of Numbers
3.1. Ascending Order
Java programs to sort a stream of numbers using Stream.sorted() method.
import java.util.stream.Stream;
public class Main
{
public static void main(String[] args)
{
Stream<Integer> numStream = Stream.of(1,3,5,4,2);
numStream.sorted()
.forEach(System.out::println);
}
}
Program output.
1
2
3
4
5
3.2. Descending Order
To sort in reverse order, use Comparator.reverseOrder() in sorted()
method.
import java.util.Comparator;
import java.util.stream.Stream;
public class Main
{
public static void main(String[] args)
{
Stream<Integer> numStream = Stream.of(1,3,5,4,2);
numStream.sorted( Comparator.reverseOrder() )
.forEach(System.out::println);
}
}
4. Sorting Stream of Strings
Java programs to sort a stream of strings using Stream.sorted() method in ascending and descending order.
Stream<String> wordStream = Stream.of("A","C","E","B","D");
wordStream.sorted() //ascending
.forEach(System.out::println);
wordStream.sorted( Comparator.reverseOrder() ) //descending
.forEach(System.out::println);
Program output.
A B C D E
E D C B A
Happy Learning !!
Comments