Contrato comparable y comparador con respecto a nulo

Comparable contrato Comparable especifica que e.compareTo(null) debe lanzar NullPointerException .

De la API :

Tenga en cuenta que null no es una instancia de ninguna clase, y e.compareTo(null) debería arrojar una NullPointerException aunque e.equals(null) devuelve false .

Por otro lado, Comparator API no menciona nada sobre lo que debe suceder al comparar null . Considera el siguiente bash de un método genérico que toma un Comparable , y devuelve un Comparator que pone null como el elemento mínimo.

 static <T extends Comparable> Comparator nullComparableComparator() { return new Comparator() { @Override public int compare(T el1, T el2) { return el1 == null ? -1 : el2 == null ? +1 : el1.compareTo(el2); } }; } 

Esto nos permite hacer lo siguiente:

 List numbers = new ArrayList( Arrays.asList(3, 2, 1, null, null, 0) ); Comparator numbersComp = nullComparableComparator(); Collections.sort(numbers, numbersComp); System.out.println(numbers); // "[null, null, 0, 1, 2, 3]" List names = new ArrayList( Arrays.asList("Bob", null, "Alice", "Carol") ); Comparator namesComp = nullComparableComparator(); Collections.sort(names, namesComp); System.out.println(names); // "[null, Alice, Bob, Carol]" 

Entonces las preguntas son:

  • ¿Es este un uso aceptable de un Comparator , o está violando una regla no escrita en cuanto a comparar null y arrojar NullPointerException ?
  • ¿Alguna vez es una buena idea incluso tener que ordenar una List contenga elementos null , o es una señal segura de un error de diseño?

Comparable no permite null simplemente porque:

 a.compareTo(b) == -b.compareTo(a) 

para todos los objetos a y b donde !a.equals(b) . Más específicamente:

 a.equals(b) ? b.equals(a) && a.compareTo(b) == 0 && b.compareTo(a) == 0 && a.hashCode() == b.hashCode() : !b.equals(a) && a.compareTo(b) != 0 && a.compareTo(b) == -b.compareTo(a) 

debe evaluar a true para cumplir con los contratos relevantes.

Entonces null no está permitido porque no puedes hacer:

 null.compareTo(a) 

Comparator es más flexible, por lo que el manejo de null es un problema específico de la implementación. Apóyalo o no según lo que quieras que haga tu Comparator .

¿Alguna vez es una buena idea incluso tener que ordenar una lista que contenga elementos nulos, o es una señal segura de un error de diseño?

Conceptualmente, null significa “nada”, y no colocar nada en una lista me parece extraño. Además, el contrato de la Lista de Java establece que

Algunas implementaciones de lista tienen restricciones sobre los elementos que pueden contener. Por ejemplo, algunas implementaciones prohíben elementos nulos

por lo tanto, ni siquiera se requiere una implementación de Lista en Java para admitir elementos nulos. En resumen, si no tiene una buena razón para poner nulo en una lista, no lo haga, y si lo hace, pruebe que realmente funciona como se esperaba.

¿Alguna vez es una buena idea incluso tener que ordenar una lista que contenga elementos nulos, o es una señal segura de un error de diseño?

Bueno, probablemente no tenga sentido que la lista contenga un Objeto nulo, pero tal vez su Lista contenga un “objeto comercial” y usted puede ordenar las diferentes propiedades del objeto comercial, algunas de las cuales pueden contener nulos.

¿Es este un uso aceptable de un Comparador?

BeanComparator le permite ordenar una propiedad en un objeto comercial, incluso si la propiedad contiene nulo, por lo que tendría que decir que es un uso aceptable de un Comparador.