Java Language Using Lambda Expressions to Sort a Collection


Example

Sorting lists

Prior to Java 8, it was necessary to implement the java.util.Comparator interface with an anonymous (or named) class when sorting a list1:

Java SE 1.2
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.

Sorting maps

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));