Java Language Ordenar una lista genérica


Ejemplo

La clase Collections ofrece dos métodos estáticos estándar para ordenar una lista:

  • sort(List<T> list) aplicable a listas donde T extends Comparable<? super T> , y
  • sort(List<T> list, Comparator<? super T> c) aplicable a listas de cualquier tipo.

Aplicar lo anterior requiere modificar la clase de elementos de lista que se están ordenando, lo que no siempre es posible. También puede ser indeseable ya que, si bien proporciona la clasificación predeterminada, es posible que se requieran otras órdenes de clasificación en diferentes circunstancias, o la clasificación es una tarea única.

Considere que tenemos la tarea de ordenar los objetos que son instancias de la siguiente clase:

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

Para utilizar Collections.sort(List<User> list) necesitamos modificar la clase de User para implementar la interfaz Comparable . Por ejemplo

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

(Aparte: muchas clases Java estándar como String , Long , Integer implementan la interfaz Comparable . Esto hace que las listas de esos elementos se puedan ordenar de forma predeterminada y simplifica la implementación de compare o compareTo en otras clases).

Con la modificación anterior, podemos ordenar fácilmente una lista de objetos de User según el orden natural de las clases. (En este caso, hemos definido que se ordenen según los valores de id ). Por ejemplo:

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]

Sin embargo, supongamos que queremos ordenar los objetos de User por name lugar de por id . Alternativamente, supongamos que no pudimos cambiar la clase para que sea implementable como Comparable .

Aquí es donde el método de sort con el argumento del Comparator es útil:

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]
Java SE 8

En Java 8 puedes usar un lambda en lugar de una clase anónima. Este último se reduce a una sola línea:

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

Además, Java 8 agrega un método de sort predeterminado en la interfaz de List , lo que simplifica la clasificación aún más.

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