2011-06-06 10 views
15

Se dice que cuando el parámetro de entrada es nulo, compareTo() debería lanzar una NullPointerException. Sin embargo, estoy implementando una clase que necesita comparar campos con el tipo de Cadena. Estos campos no necesitan ser obligatorios. Me pregunto en este caso,¿Qué debe comparar intTo() cuando la cadena del parámetro es nula?

1) ¿Qué debo devolver cuando la entrada es nula? ¿Debería cualquier cadena no nula lexicográficamente más grande o más pequeña que nula?

y

2) Si esto se considera una mala práctica, ¿hay argumentos que apoyan? ¿Debo forzar al usuario a usar cadenas vacías en su lugar? Si utiliza una cadena vacía, ¿no confundirá el caso en el que el campo no es aplicable y el caso en el que el campo está vacío? Y si se debe emitir una excepción, entonces, salvo advertir al usuario en el manual, ¿qué más podría/debo hacer?

EDITAR: Puede que no me exprese claramente aquí, pero en el programa que estoy implementando, las cadenas que podrían ser nulas son todos los campos o una clase, que no debería ser nula. En otras palabras, los objetos que se comparanA() no podrían ser nulos, solo podrían ser sus campos privados. Entonces, en este caso, creo que si implemento compareTo() correctamente, no violaría el requisito transitivo ya que las clases con campos nulos se considerarían siempre iguales. ¿Estoy en lo cierto o estoy interpretando esto mal?

¡Gracias a todos por las respuestas!

+0

Cómo implementarlo mejor: http://stackoverflow.com/questions/481813/how-to-simplify-a-null-safe-compareto-implementation –

Respuesta

12

Sí, no hay ningún problema al permitir null para campos de instancia, solo asegúrese de que se haya definido su orden de clasificación. Lo más natural sería ponerlo antes o después de todas las cuerdas reales, pero podrías hacer cualquier cosa aquí, solo hazlo de manera consistente. (Por ejemplo, usted podría ordenar null como "null".)

Aquí es un ejemplo de implementación de un solo miembro:

class Example implements Comparable<Example> { 

    @Nullable 
    private String member; 

    // TODO: getter, setter, constructor, ... 

    public int compareTo(Example that) { 
     if(this.member == null) 
     if(that.member == null) 
      return 0; //equal 
     else 
      return -1; // null is before other strings 
     else // this.member != null 
     if(that.member == null) 
      return 1; // all other strings are after null 
     else 
      return this.member.compareTo(that.member); 
    } 
} 

Tenga en cuenta que la especificación de Comparable.compareTo() sólo tiene una restricción para o.compareTo(null) (que debería comportarse como - null.compareTo(o)), pero no sobre cómo se manejan los campos null (no menciona campos en absoluto, por lo que una clase puede devolver lo que quiera, siempre que la antisimetría, la reflexividad y la transitividad estén garantizadas).

+0

Bueno, existe el problema de que no está de acuerdo con la especificación ;-) – EJP

+2

@EJP: La especificación de 'compareTo' no dice nada sobre cómo (o incluso si) comparar campos de instancia de los objetos. –

+0

La especificación de compareTo() dice 'e.compareTo (null) debería arrojar una NullPointerException'. – EJP

23

De Javadoc para Comparable

Tenga en cuenta que nulo no es una instancia de cualquier clase y e.compareTo (nulo) debería lanzar una NullPointerException a pesar de que e.equals (nulo) devuelve falso .

7

que sería una mala práctica de no lanzar una excepción, ya que viola la naturaleza transitiva antisimétrico de compareTo.

De Comparable.compareTo documentación:

El implementador debe garantizar sgn (x.compareTo (y)) == -sgn (y.compareTo (x)) para todo x e y. (Esto implica que x.compareTo (y) debe lanzar una excepción si y sólo si y.compareTo (x) lanza una excepción.)

El implementador también debe garantizar que la relación es transitiva: (x.compareTo (y)> 0 & & y.compareTo (z)> 0) implica x.compareTo (z)> 0.

Finalmente, el implementador debe garantizar que x.compareTo (y) == 0 implica que sgn (x.compareTo (z)) == sgn (y.compareTo (z)), para todo z.

que es más importante, que es una mala idea usar compareTo en sus objetos para compararlos con las cadenas, por la misma razón: sign(obj.compareTo(str)) != -sign(str.compareTo(obj)). Implemente un Comparator personalizado y haga lo que desee en él.

+0

¡Gracias! Sin embargo, en el programa que estoy implementando, las cadenas que podrían ser nulas son todas partes o una clase, que no debería ser nula. Entonces, en este caso, creo que si implemento compareTo() correctamente, no violaría el requisito transitivo ya que las clases con campos nulos se considerarían siempre iguales. ¿Estoy en lo cierto o estoy interpretando esto mal? –

+0

Está perfectamente bien comparar dos instancias de una clase que pueden o no tener algunos campos de instancia establecidos. Solo asegúrate de implementarlo de forma transitiva. ES DECIR. c1.compareTo (c2) == -c2.compareTo (c1) – ykaganovich

+1

Solo por terminología: la condición 'c1.compareTo (c2) == -c2.compareTo (c1)' se llama antisimetría, no transitividad. La transitividad es principalmente la segunda condición en su cotización (y tal vez también la tercera). –

3

Dado que la documentación de compareTo indica que debe arrojar un NullPointerException, debe seguir esas pautas para que su implementación sea coherente con la documentación de la interfaz. Esto también maneja las preguntas de si las cadenas no nulas son lexicográficamente más pequeñas o más grandes que null.

Tiene un par de opciones sobre cómo manejar esto. Si el vacío y el no aplicable son diferentes, entonces probablemente deba envolver el campo de cadena en su propia clase de campo. Por ejemplo, supongamos que puede crear un tipo de MyField que podría tener un método isApplicable, que indica si el campo es aplicable a este caso (o algo similar). O podría reconsiderar su diseño y asegurarse de que una cadena vacía y N/A realmente sean dos cosas diferentes. Si lo son, necesitas una manera de diferenciar entre los dos.

3

Debe decidir si nulo es mayor que o menor que un valor no nulo. Puede diseñar compareTo para satisfacer las necesidades del orden natural de su clase, por lo tanto, no es una mala práctica.

Cuestiones relacionadas