Prior to Java 8, it was necessary to implement the java.util.Comparator
interface with an anonymous (or named) class when sorting a list1:
List<Person> people = ...
Collections.sort(
people,
new Comparator<Person>() {
public int compare(Person p1, Person p2){
return p1.getFirstName().compareTo(p2.getFirstName());
}
}
);
Starting with Java 8, the anonymous class can be replaced with a lambda expression. Note that the types for the parameters p1
and p2
can be left out, as the compiler will infer them automatically:
Collections.sort(
people,
(p1, p2) -> p1.getFirstName().compareTo(p2.getFirstName())
);
The example can be simplified by using Comparator.comparing
and method references expressed using the ::
(double colon) symbol.
Collections.sort(
people,
Comparator.comparing(Person::getFirstName)
);
A static import allows us to express this more concisely, but it is debatable whether this improves overall readability:
import static java.util.Collections.sort;
import static java.util.Comparator.comparing;
//...
sort(people, comparing(Person::getFirstName));
Comparators built this way can also be chained together. For example, after comparing people by their first name, if there are people with the same first name, the thenComparing
method with also compare by last name:
sort(people, comparing(Person::getFirstName).thenComparing(Person::getLastName));
1 - Note that Collections.sort(...) only works on collections that are subtypes of List
. The Set
and Collection
APIs do not imply any ordering of the elements.
You can sort the entries of a HashMap
by value in a similar fashion. (Note that a LinkedHashMap
must be used as the target. The keys in an ordinary HashMap
are unordered.)
Map<String, Integer> map = new HashMap(); // ... or any other Map class
// populate the map
map = map.entrySet()
.stream()
.sorted(Map.Entry.<String, Integer>comparingByValue())
.collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue(),
(k, v) -> k, LinkedHashMap::new));