So, you have some instances of a class and you want to sort them based on a specific field, but without using the natural order of such a field. That is, you rather need to provide a specific comparator for such a field.
public class Person {
private Address address;
private LocalDate birthday;
//getters and setters
}
public class Address {
private String city;
private String state;
private String street;
//getters and setters
}
Let's first clarify how we could sort instances of Person based on the natural order of one of its fields, e.g. the birthday.
persons.stream().sort(Comparator.comparing(Person::getBirthday));
Cool. Now, let's consider how to order Person
based on their Address
.
Better, let's imagine to have to sort them based on the city and street without
considering the state.
We then need a customised comparator to order Address
. We can achieve this
by chaining the Comparator above:
Comparator<Address> byCityAndStreet =
Comparator.comparing(Address::getCity).thenComparing(Address::getStreet);
This first compares Address
based on the city field, then if this is not decisive
(i.e. two addresses with the same city) compares them based on their street.
Perfect, the next step is to use this comparator to sort the Person
.
This is possible thanks to another method of the Comparator
interface:
comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)
.
In this method, keyExtractor
specify how to extract the key
used in the comparison, then applies keyComparator
to it!
persons.stream().sort(Comparator.comparing(Person::getAddress), byCityAndStreet);
And here we are, we have successfully sorted java objects based on a custom comparator applied to two fields of a nested object.