Ordenar Listas en Java

Ordenar Listas en JavaSi eres programador seguramente te has encontrado con el problema de Ordenar Listas, pero ¿Estamos utilizando la solución correcta o estamos reinventando la rueda? Pues en este artículo hablaremos de las formas estándares que ofrece Java para ordenar listas sin tener que programar más de lo requerido.

Básicamente Java ofrece dos interfaces que serán claves para realizar un ordenamiento simple, las cuales son Comparator  y Comparable, estas dos interfaces atienden contextos diferentes en el ordenamiento de las listas, pues existen dos escenarios concretos (Si ya conoces la teoría puedes brincarte a la última sección):

Objetos preparados para ser Ordenados

El escenario más simple para ordenar un Lista, es cuando sus elementos están preparados para ser ordenados, esto implica que los elementos de la lista implementan la interface Comparable. Al implementar esta interface, las clases deberá implementar el método public interface Comparable<T>, el cual sirve para comprar un objeto contra otro, este método recibe como parámetro otro objeto, el cual utilizaremos para comprarlo contra el actual para responder con un entero, el cual deberá ser:

  • < 0 (Menor que cero): cuando el objeto actual es menor que el otro
  • = 0 (Igual a cero): cuando los objetos son iguales
  • > 0 (Mayor que cero): cuando el otro objeto es mayor.

Cuando una clase implementa Comparable entonces podemos decir que está preparada para ser Ordenada y ordenarla será tan simple como hacer lo siguiente:

Collections.sort(lstSortEmployees);

Asumiendo que la variable lstSortEmployees es una lista de objetos que implementan Comparable.

Objetos que no están preparados para ser Ordenados

Por otra parte, las clases que no implementan Comparable no podrán ser ordenadas de forma natural, por lo que tendremos que recurrir a la interface Comparator, la cual sirve para crear una clase externa que ayude al ordenamiento de los Objetos sin modificar la estructura de las clases existentes. Para lo cual será necesario crear una nueva clase que implementa la interface Comparator y con ello el método int compare(T o1, T o2), el cual funciona exactamente igual que el de la interface Comparable, solo que este recibe como parámetros los dos objetos que será comparados.

Ahora bien, si queremos ordenar una lista mediante este método podríamos hacerlo de la siguiente manera:

Collections.sort(lstEmployees, new EmployeeComparator());

Donde lstEmployees es la lista de objetos a ordenar y EmployeeComparator es una clase que implementa Comparator. Aunque también podríamos ahorrarnos la creación de una nueva clase y crear una clase anónima, como podemos ver a continuación:

Collections.sort(lstEmployees, new Comparator<Employee>(){

    @Override
    public int compare(Employee o1, Employee o2) {
        return o1.getName().compareToIgnoreCase(o2.getName());
    }
});

Veamos que este último ejemplo instanciamos la interface Comparator al vuelo y definimos el método compare para determinar cuál empleado es mayor que cual.

Finalmente, Java 8 ofrece una forma muchos más simple de ordenar los objetos utilizado Lamba Expresión, por lo cual en lugar de crear un Comparator, solo definimos la estrategia para comparar los objetos, veamos cómo quedaría:

Collections.sort(lstEmployees, (x, y) -> x.getName().compareToIgnoreCase(y.getName()));

Mediante lamba expresión definimos solamente como los objetos deberán ser comparados.

Un ejemplo práctico:

Muy bonita la explicación, pero pasemos mejor a un ejemplo práctico. Vamos a ver un ejemplo rápido para realizar los 3 tipos de ordenamientos que vimos anteriormente. Todo el código fuente lo puedes encontrar el GiHub: https://github.com/oscarjb1/SortList.git

package com.osb.sortlist;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @author Oscar Blancarte <oscarblancarte3@gmail.com>
 */
public class SortMain {

    private static final String[] NAMES = new String[]{
        "Oscar Blancarte",
        "Juan Perez",
        "Gabriel German",
        "Liliana Castro",
        "Alfredo Alvarado",
        "Rebeca Hernandez",
        "Sofia Galindo",
        "Samuel Alvarez",
        "Manuel Orozco"
    };

    public static void main(String[] args) {

        //Ordenar empleados que estan preparados para ser ordenados
        List<SortEmployee> lstSortEmployees = getSorteableEmployeeList();
        Collections.sort(lstSortEmployees);
        printList("lstSortEmployess ==>", lstSortEmployees);

        //Ordenar empleados que no estan preparados para ser ordenados
        List<Employee> lstEmployees = getEmployeeList();
        Collections.sort(lstEmployees, new Comparator<Employee>(){
            @Override
            public int compare(Employee o1, Employee o2) {
                return o1.getName().compareToIgnoreCase(o2.getName());
            }
        });
        printList("lstEmployees ==>", lstEmployees);

        //Ordenas Empleados con Lambda Expresion
        Collections.sort(lstEmployees, (x, y) -> x.getName().compareToIgnoreCase(y.getName()));
        printList("lstEmployees Lambda ==>", lstEmployees);
    }

    private static void printList(String title, List list) {
        System.out.println(title);
        list.forEach(x -> System.out.println("\t" + x.toString()));
        System.out.println("");
    }

    private static List<Employee> getEmployeeList() {
        List<Employee> employees = new ArrayList<>();
        for (String name : NAMES) {
            employees.add(new Employee(name));
        }
        return employees;
    }

    private static List<SortEmployee> getSorteableEmployeeList() {
        List<SortEmployee> employees = new ArrayList<>();
        for (String name : NAMES) {
            employees.add(new SortEmployee(name));
        }
        return employees;
    }
}

La siguiente clase representa un empleado que no está preparado para ser ordenado:

package com.osb.sortlist;

/**
 * @author Oscar Blancarte <oscarblancarte3@gmail.com>
 */
public class Employee {
    private String name;
    
    public Employee(){
    }

    public Employee(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return name;
    }
}

Este otro empleado si está preparado para ser ordenado:

package com.osb.sortlist;

/**
 * @author Oscar Blancarte <oscarblancarte3@gmail.com>
 */
public class SortEmployee implements Comparable<SortEmployee> {
    
    private String name;

    public SortEmployee( String name) {
        this.name = name;
    }

    @Override
    public int compareTo(SortEmployee employee1) {
        return this.name.compareToIgnoreCase(employee1.name);
    }

    @Override
    public String toString() {
        return name;
    }
}

El resultado de la ejecución del proyecto nos da el siguiente resultado:

lstSortEmployess ==>
    Alfredo Alvarado
    Gabriel German
    Juan Perez
    Liliana Castro
    Manuel Orozco
    Oscar Blancarte
    Rebeca Hernandez
    Samuel Alvarez
    Sofia Galindo

lstEmployees ==>
    Alfredo Alvarado
    Gabriel German
    Juan Perez
    Liliana Castro
    Manuel Orozco
    Oscar Blancarte
    Rebeca Hernandez
    Samuel Alvarez
    Sofia Galindo

lstEmployees Lambda ==>
    Alfredo Alvarado
    Gabriel German
    Juan Perez
    Liliana Castro
    Manuel Orozco
    Oscar Blancarte
    Rebeca Hernandez
    Samuel Alvarez
    Sofia Galindo

Como puedes ver, estamos realizando tres ordenamientos, el primero es con una lista de SortEmployee, el segundo ordenamiento es con una lista de Employee, y la tercera es utilizando lamba expresión.

Te invito a que veas mi curso de Java Core, en el cual enseñamos Java desde cero con las mejores prácticas y un proyecto final.

Espero que esta explicación sea lo suficientemente clara como para aclarar cualquier duda que tuvieras, pero si no es así, recuerda que puedes escribirme en los comentarios y con gusto te responderé.

12 thoughts to “Ordenar Listas en Java”

  1. Buen artículo!!
    Ahora que estoy a tope con la certificación de java 8, añadir que todas las Wrapper classes implementan Comparable y Serializable, y que por tanto al crear una List de una wrapper class nos permitirá por tanto hacer el sort para ordenarla.
    Un saludo.

    1. Hola Silvia, tu comentario es absolutamente cierto y te felicito, porque veo que vas muy bien con tu certificación. Recuerdo cuando yo me certifique en Java… pffff!!!, hace muchos años, verás que cuando tengas tu certificación te sentirás muy bien.
      Te invito a que te suscribas a mi blog y así poderte mandar más actualizaciones de mi blog, también puedes ver más artículos de Java 8 en: https://www.oscarblancarteblog.com/tag/java8/
      Saludos.

      1. jejeje gracias!!! la verdad es que estoy de los nervios porque me examino el próximo mes!!! que ganas tengo ya de hacer el examen y tener la certificación.

        Pues me viene genial ese enlace a los artículos de java 8 🙂 muchas gracias! les hiré mirando poco a poco para repasar los conceptos.

        Un saludo.

    2. Cómo podría hacer si quiero ordenar un arraylist de tipo proveedor, donde proveedor es una clase que tiene los atributos nombre y ciudad.

      Lo que quiero lograr es ordenar el arraylist alfabéticamente por nombre

      1. Pues es lo mismo del ejemplo, en la clase Comparable debes definir como ordenar los elementos, recuerda que el Comparable recibirá el Proveedor como parámetro, y desde allí defines mediante los calores -1, 0 y 1 cual es mayor.

  2. Hola, gracias por la publicación, me ayudó mucho.

    Me queda una duda, como haría si quisiera ordenar una lista de personas pero con un criterio, por ejemplo primero por apellido, luego por nombre y luego por edad.

    Saludos

    1. podrías utilizar el API de streams para filtrar elementos, podrías hacer algo así como list.stram().filter(item -> item.getNombre().equals("oscar") && item.getApellido().equals("peres"))

  3. Hola, si me pudieras ayudar cómo ordenar una “listaReservas” que contiene objetos del tipo Reservacion, donde alguno de los atributos de Reservacion esta mapeado a otra clase tipo Hotel, y finalmente la clase Hotel tiene los atributos id (entero), nombreHotel (Cadena)…….Entonces la lista “Reservas” deseo ordenarla ascendentemente por uno de los atributos de su objeto anidado “Hotel”…es decir:
    ListaReservas.get(index).getHotel().getNombreHotel();

    Al final lo que necesito es todos elementos de la lista queden ordenados con base a ese atributo del objeto anidado Hotel dentro de Reservacion.
    Lo anterior es porque estoy comparando dos listas entre si , y necesito tener certeza que al comparar elemento por elemento de ambas listas esta el tienen el mismo dato para el indice 0,1,2,3…N de ambas listas.

    1. Lo que necesitas es analizar la interfaz Comparator, esta te permite definir la forma en que un objeto más complejo como el tuyo deberá ser comparador contrar otro, si revisas por internet veras que hay mucha documentación al respecto.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *