Guía Detallada sobre Comparator y Comparable en Java

En Java, las interfaces Comparator y Comparable se utilizan para definir cómo se deben comparar los objetos, permitiendo el ordenamiento de colecciones o arreglos. Esta guía explica cómo funcionan estas interfaces, cómo implementarlas y cómo elegir la más adecuada según el contexto.


¿Qué es Comparable?

La interfaz Comparable se utiliza para definir un orden natural para los objetos de una clase. Al implementar esta interfaz, puedes especificar cómo se comparan los objetos de esa clase.

Método clave:

La interfaz Comparable tiene un solo método:

int compareTo(T o);

Este método devuelve:

Ejemplo de Comparable:

Supongamos que tienes una clase Persona con atributos nombre y edad, y deseas ordenar por edad.

class Persona implements Comparable<Persona> {
    private String nombre;
    private int edad;

    public Persona(String nombre, int edad) {
        this.nombre = nombre;
        this.edad = edad;
    }

    @Override
    public int compareTo(Persona otra) {
        return Integer.compare(this.edad, otra.edad);
    }

    @Override
    public String toString() {
        return nombre + " (" + edad + " años)";
    }
}

public class EjemploComparable {
    public static void main(String[] args) {
        List<Persona> personas = Arrays.asList(
            new Persona("Ana", 25),
            new Persona("Luis", 30),
            new Persona("Juan", 20)
        );

        Collections.sort(personas);
        System.out.println(personas);
    }
}

Salida:

[Juan (20 años), Ana (25 años), Luis (30 años)]

¿Qué es Comparator?

La interfaz Comparator se utiliza para definir un orden personalizado para los objetos, independiente del orden natural definido en la clase.

Método clave:

La interfaz Comparator tiene un método principal:

int compare(T o1, T o2);

Este método devuelve:

Ejemplo de Comparator:

Supongamos que ahora deseas ordenar las personas por nombre en lugar de edad.

import java.util.Comparator;

class ComparadorPorNombre implements Comparator<Persona> {
    @Override
    public int compare(Persona p1, Persona p2) {
        return p1.getNombre().compareTo(p2.getNombre());
    }
}

public class EjemploComparator {
    public static void main(String[] args) {
        List<Persona> personas = Arrays.asList(
            new Persona("Ana", 25),
            new Persona("Luis", 30),
            new Persona("Juan", 20)
        );

        personas.sort(new ComparadorPorNombre());
        System.out.println(personas);
    }
}

Salida:

[Ana (25 años), Juan (20 años), Luis (30 años)]

Diferencias entre Comparable y Comparator

CaracterísticaComparableComparator
Ubicación del códigoDentro de la clase que se compara.En una clase separada.
OrdenNatural (predeterminado).Personalizado (dinámico).
ImplementaciónUsa el método compareTo.Usa el método compare.
Cambios en el código fuenteNecesita modificar la clase.No requiere cambios en la clase.

¿Cuál usar y cuándo?

  1. Usa Comparable si:

    • El orden es natural y siempre será el mismo.
    • Controlas la clase que está siendo ordenada.
  2. Usa Comparator si:

    • Necesitas un orden diferente al natural.
    • No puedes o no quieres modificar la clase original.
    • Necesitas varios criterios de comparación.

Uso avanzado de Comparator

Desde Java 8, Comparator incluye métodos estáticos y por defecto que simplifican su uso.

1. Comparator.comparing()

Puedes crear un Comparator en una línea utilizando Comparator.comparing:

personas.sort(Comparator.comparing(Persona::getNombre));

2. Comparaciones múltiples

Puedes encadenar comparaciones usando thenComparing:

personas.sort(
    Comparator.comparing(Persona::getEdad).thenComparing(Persona::getNombre)
);

Esto primero ordena por edad y luego por nombre si las edades son iguales.

3. Comparación inversa

Para invertir el orden, usa reversed():

personas.sort(Comparator.comparing(Persona::getEdad).reversed());

Ejercicios propuestos

  1. Implementa la interfaz Comparable para una clase Producto y ordénalos por precio.
  2. Crea un Comparator para la clase Producto que ordene por nombre.
  3. Escribe un programa que use un Comparator para ordenar objetos Empleado primero por salario y luego por nombre.
  4. Usa Comparator.comparing para ordenar una lista de libros por título.
  5. Implementa una comparación inversa utilizando Comparator.reversed() para ordenar fechas de manera descendente.

Conclusión

Tanto Comparable como Comparator son herramientas fundamentales para trabajar con colecciones en Java. Comparable es ideal para definir un orden natural, mientras que Comparator proporciona flexibilidad para ordenar de múltiples maneras. Dominar estas interfaces te permitirá manejar el ordenamiento de objetos de manera eficiente, lo cual es esencial en muchos proyectos. ¡Sigue practicando y explorando nuevas formas de aplicar estos conceptos!