Sorting Lists in Java

Learn how to sort a List in java. Use Java 8 Lambdas to compose sort conditions.

sorting a collection

“You can only be afraid of what you think you know.”
― Jiddu Krishnamurti

1. Introduction

Sorting a list is a very common requirement when programming in java. Out of the box, java provides for sorting using a performant algorithm so there is no need to roll your own algo for the purpose. In this article, we demonstrate how to sort a list in java.

2. Sort a List of Strings

The List interface provides a default implementation of a sort() method which can be used to sort objects by their natural ordering (for a String, this refers to alphabetical ordering). This code is as simple as it gets for ordering a list.

List<String> alist = Arrays.asList("apple", "guava", "orange",
                                   "mango", "grapes");
System.out.println("List: " + alist);
alist.sort(null);
System.out.println("Sorted list: " + alist);
# prints
       List: [apple, guava, orange, mango, grapes]
Sorted list: [apple, grapes, guava, mango, orange]

The same code uses natural ordering for numbers when you sort a list of integers.

List<String> blist = Arrays.asList(95, 277, 23, 134, 9, 33);
System.out.println("       List: " + blist);
Collections.sort(blist);
System.out.println("Sorted list: " + blist);
# prints
       List: [95, 277, 23, 134, 9, 33]
Sorted list: [9, 23, 33, 95, 134, 277]

3. Ignoring Case

What if you want to sort a list of strings regardless of case? One way is to provide a comparator function to the sort() method.

List<String> alist = Arrays.asList("apple", "Guava", "Orange",
                                   "mango", "grapes");
System.out.println("         List: " + alist);
alist.sort(null);
System.out.println("  Sorted list: " + alist);
alist.sort((x, y) -> {
        return x.compareToIgnoreCase(y);
    });
System.out.println("Ignoring case: " + alist);
# prints
         List: [apple, Guava, Orange, mango, grapes]
  Sorted list: [Guava, Orange, apple, grapes, mango]
Ignoring case: [apple, grapes, Guava, mango, Orange]

Using Java 8 Lambda Method References, we can rewrite the sort() invocation as:

alist.sort(String::compareToIgnoreCase);

4. Using Object Properties for Sorting

Let us now look at a sample object class, a list of which we want to sort. The class represents a User and we would like to be able to sort by various properties.

public class User {
    private String firstName;
    private String lastName;
    private int age;

    public User(String firstName,String lastName,int age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    }

    public String toString() {
    StringBuilder sbuf = new StringBuilder();
    sbuf.append('(').append(this.firstName)
        .append(',').append(this.lastName)
        .append(',').append(this.age)
        .append(')');
    return sbuf.toString();
    }

    // standard getters and setters here
}

And here is a list of these User objects that we want to sort. We use a lambda to specify the sort condition.

List<User> users = Arrays.asList(new User("Chris", "Pruitt", 34),
                                 new User("Matt", "Bates", 15),
                                 new User("John", "Wagner", 82),
                                 new User("Vernon", "McGuire", 31),
                                 new User("Mary", "Bates", 37),
                                 new User("Mary", "Bates", 23));
System.out.println("       List: " + users);
users.sort((x, y) -> {
        return x.getLastName().compareToIgnoreCase(y.getLastName());
    });
System.out.println("Sorted List: " + users);
# prints
       List: [(Chris,Pruitt,34), (Matt,Bates,15), (John,Wagner,82), (Vernon,McGuire,31), (Mary,Bates,37), (Mary,Bates,23)]
Sorted List: [(Matt,Bates,15), (Mary,Bates,37), (Mary,Bates,23), (Vernon,McGuire,31), (Chris,Pruitt,34), (John,Wagner,82)]

5. Assembling Sort Conditions

Sometimes the need arises to be able to sort by multiple properties. In the above example, suppose we want to sort by last name and age. Here is one way to implement the sort condition.

users.sort((x, y) -> {
        int r = x.getLastName().compareToIgnoreCase(y.getLastName());
        if ( r == 0 ) r = Integer.compare(x.getAge(),y.getAge());
        return r;
    });

However, the disadvantage with such a compare function is that it can get big and hairy when there are many sort conditions. Wouldn’t it be nice if we could just assemble different sort conditions, perhaps on demand? Basically build a sort condition at runtime?

There are several ways of implementing such a sort condition. One way is to use enums and has been described elsewhere.

Here is another way to do the same using java 8 lambdas. First, let us declare some sort conditions that we can use to compose larger conditions. This one compares by the user’s last name.

Comparator<User> f1 = (x, y) -> x.getLastName().compareToIgnoreCase(y.getLastName());

And these conditions compare by the first name and the age:

Comparator<User> f2 = (x, y) -> x.getFirstName().compareToIgnoreCase(y.getFirstName());
Comparator f3 = (x, y) -> Integer.compare(x.getAge(),y.getAge());

To combine conditions, we can use thenComparing() to chain conditions as follows:

Here is a condition to compare by last name and then by the first name.

Comparator<User> f4 = f1.thenComparing(f2);

Why not add age to the mix?

Comparator<User> f5 = f1.thenComparing(f2).thenComparing(f3);

Once you have the comparator condition assembled properly, you can pass the lambda to the sort(() method.

users.sort(f5);
System.out.println("f5 => " + users);
# prints
f5 => [(Mary,Bates,23), (Mary,Bates,37), (Matt,Bates,15), (Vernon,McGuire,31), (Chris,Pruitt,34), (John,Wagner,82)]

Easily reverse the sort condition to make the sort order ascending or descending.

Comparator<User> f6 = f5.reversed();
users.sort(f6);
System.out.println("f6 => " + users);
# prints
f6 => [(John,Wagner,82), (Chris,Pruitt,34), (Vernon,McGuire,31), (Matt,Bates,15), (Mary,Bates,37), (Mary,Bates,23)]

Conclusion

Sorting a java list is quite easy. You can use the sort() method and pass in a function or lambda to get the sort order just the way you want. You can also use the lambda facilities to assemble the sort order in any manner from smaller lambdas.