DEV Community

Elías Canales
Elías Canales

Posted on

Implementando Comparable

La interfaz Comparable no solo permite saber si dos objetos son iguales, además, podemos saber cual es menor o mayor. Esta interfaz debe ser implementada explícitamente, a diferencia de equals() que se hereda de Object.

public int compareTo(T otro)
Enter fullscreen mode Exit fullscreen mode

Con esta interfaz habilitamos el uso de funciones que necesitan de objetos comparables. Por ejemplo, los algoritmos de ordenación necesitan poder comparar objetos y saber si es igual, mayor o menor.

También hay clases que para poder funcionar deben de poder comparar objetos, por ejemplo, TreeSet. Si construyes un TreeSet con objetos que no implementan la interfaz Comparable, veras que te dará una advertencia, básicamente porque no va a funcionar correctamente.

new TreeSet<>(Comparator.comparingInt(User::age));
Enter fullscreen mode Exit fullscreen mode

Aunque también esta la opción de pasar una función de comparación, pero tienes que tener en cuenta que si en otro punto del código, vas a volver a necesitarlo, lo mejor sería implementarla directamente en el objeto.

El contrato de esta interfaz debería cumplir:

  1. Tener simetría: Tenemos un objeto X y uno Y, si hacemos X.compareTo(Y) y obtenemos un mayor a 0. Cuando hagamos un Y.compareTo(X) tenemos que obtener un número negativo. Esto asegura que si X es mayor que Y, entonces Y sera menor que X. (Relativo a esto si X.compareTo(Y) da excepción, Y.compareTo(X) también debería dar excepción).
  2. Propiedad transitiva: Si tenemos que X > Y > Z entonces X > Z. Por lo que, X.compareTo(Y) > 0, y Y.compareTo(Z) > 0, entonces X.compareTo(Z) > 0.
  3. Por último, si dos objetos son iguales X.compareTo(Y) == 0. Entonces, el resultado contra un tercer objeto de X y Y debe ser igual. signo(X.compareTo(Z)) == signo(Y.compareTo(Z))
  4. Es recomendable que si dos objetos son iguales para el equals() que también lo sean para el compareTo (X.compareTo(Y) == Y.compareTo(X)).

Cuando pongo que es mayor/menor a 0 o que se mira el signo(), es porque el compareTo no va a devolver 0, 1 y -1. Va a devolver 0, mayor a 0 o menor a 0.

Para implementar este método iremos evaluando cada una de las propiedades más relevantes del objeto, hasta encontrar una que no sea igual, y devolveremos la respuesta.

private static final Comparator<Box> COMPARATOR = 
  Comparator.comparingInt(Box::model)
        .thenComparingDouble(Box::width)
        .thenComparingDouble(Box::length)
        .thenComparingDouble(Box::height);

@Override
public int compareTo(Box b) {
    return COMPARATOR.compare(this, b);
}
Enter fullscreen mode Exit fullscreen mode

A la hora de comparar es mejor utilizar los métodos estáticos de los tipos para comparar que usar '<' y '>'.

Referencias

Top comments (0)