Sorting a generic list

suggest change

The Collections class offers two standard static methods to sort a list:

Applying the former requires amending the class of list elements being sorted, which is not always possible. It might also be undesirable as although it provides the default sorting, other sorting orders may be required in different circumstances, or sorting is just a one off task.

Consider we have a task of sorting objects that are instances of the following class:

public class User {
    public final Long id;
    public final String username;

    public User(Long id, String username) {
        this.id = id;
        this.username = username;
    }

    @Override
    public String toString() {
        return String.format("%s:%d", username, id);
    }
}

In order to use Collections.sort(List<User> list) we need to modify the User class to implement the Comparable interface. For example

public class User implements Comparable<User> {
    public final Long id;
    public final String username;

    public User(Long id, String username) {
        this.id = id;
        this.username = username;
    }

    @Override
    public String toString() {
        return String.format("%s:%d", username, id);
    }

    @Override
    /** The natural ordering for 'User' objects is by the 'id' field. */
    public int compareTo(User o) {
        return id.compareTo(o.id);
    }
}

(Aside: many standard Java classes such as String, Long, Integer implement the Comparable interface. This makes lists of those elements sortable by default, and simplifies implementation of compare or compareTo in other classes.)

With the modification above, the we can easily sort a list of User objects based on the classes natural ordering. (In this case, we have defined that to be ordering based on id values). For example:

List<User> users = Lists.newArrayList(
    new User(33L, "A"),
    new User(25L, "B"),
    new User(28L, ""));
Collections.sort(users);

System.out.print(users);
// [B:25, C:28, A:33]

However, suppose that we wanted to sort User objects by name rather than by id. Alternatively, suppose that we had not been able to change the class to make it implement Comparable.

This is where the sort method with the Comparator argument is useful:

Collections.sort(users, new Comparator<User>() {
    @Override
    /* Order two 'User' objects based on their names. */
    public int compare(User left, User right) {
        return left.username.compareTo(right.username);
    }
});
System.out.print(users);
// [A:33, B:25, C:28]

In Java 8 you can use a lambda instead of an anonymous class. The latter reduces to a one-liner:

Collections.sort(users, (l, r) -> l.username.compareTo(r.username));

Further, there Java 8 adds a default sort method on the List interface, which simplifies sorting even more.

users.sort((l, r) -> l.username.compareTo(r.username))

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:



Table Of Contents