2011-01-05 20 views
11

Tengo dolores de cabeza cuando tengo que escribir casi 10 líneas de código para decir 2 Objects are equal, when their type is equal and both's attribute is equal. Puede ver fácilmente que en esta forma de escritura el número de líneas aumenta drásticamente con su número de atributos.Java: howto write equals() más corto

public class Id implements Node { 

     private String name; 

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

     public boolean equals(Object o) { 
       if (o == null) 
         return false; 
       if (null == (Id) o) 
         return false; 
       Id i = (Id) o; 
       if ((this.name != null && i.name == null) || (this.name == null && i.name != null)) 
         return false; 
       return (this.name == null && i.name == null) || this.name.equals(i.name); 
     } 

} 
+2

Por favor, consulte mi respuesta para una implementación adecuada de iguales. Lanzar algo al tipo incorrecto le da una excepción de tiempo de ejecución (ClassCastException), no nulo. Por favor, lea java efectivo para una *** explicación *** fantástico. – Tom

+1

Btw - Vinculado al capítulo real en java efectivo en mi respuesta :-). – Tom

Respuesta

10

Si utiliza Eclipse, haga clic en " Fuente "->" generar hashCode() y es igual a() ". Hay muchas opciones para crear equals() automáticamente.

+3

En mi experiencia, los generados tienden a perder sincronía con la clase. Pero eso no es nada que una buena revisión de código no pueda solucionar. Y supongo que los escritos a mano pueden tener fácilmente el mismo problema. – sblundy

+0

la manera más fácil. no hay necesidad de preocuparse por algo que no es directamente importante. De todos modos, el código generado no es mucho más pequeño que el mío. Parece que es el caso normal en Java ... – erikbwork

+0

Permítanme decir dos cosas sobre esta respuesta: (1) no se deje engañar por pensar que el código generado siempre es correcto. (2) La legibilidad es otra preocupación. – Tom

9

Hay bibliotecas que lo harán por usted. Por ejemplo, commons-lang tiene EqualsBuilder

Además, estas dos líneas parecen hacer lo mismo:

  if (o == null) 
        return false; 
      if (null == (Id) o) 
        return false; 

Tal vez que quería decir esto:

  if (o == null) 
        return false; 
      if (this == o) 
        return true; 
+0

El primero si debe verificar si el param, el segundo si debe verificar el tipo. Cuando supe Java, un molde arrojó nulo en el tipo que no coincide. Pero a través de mis pruebas unitarias ya me enteré de que este ya no es el caso. – erikbwork

+0

@erikb: Eso daría como resultado una ClassCastException. Puedes simplemente verificar si las clases son iguales, así: this.getClass() == o.getClass(). Sub/súper clases agregar algunas arrugas sin embargo. – sblundy

+0

@sblundy: por favor, lea java efectivo que (IIRC) tiene una explicación de por qué debería usar 'instanceof' en lugar de' getClass() '. Josh Bloch hace un gran trabajo al explicar la forma correcta de implementar 'equals()' y si no lo has leído seguramente aprenderás algo. – Tom

12

La biblioteca de guayaba de Google tiene la clase Objects con Objects#equal que maneja la nulidad. Realmente ayuda a hacer las cosas más pequeñas. Con su ejemplo, escribiría:

@Override public boolean equals(Object other) { 
    if (!(other instanceof Id)) { 
    return false; 
    } 
    Id o = (Id) other; 
    return Objects.equal(this.name, o.name); 
} 

La documentación es here.

También tenga en cuenta que hay Objects#hashCode y Objects#toStringHelper para ayudar con hashCode y toString también!

También vea Effective Java 2nd Edition on how to write equals().

+1

He actualizado el enlace en mi respuesta para vincular al capítulo correspondiente en Effective Java! Ahora no hay excusa para no leerlo :-). – Tom

+0

JDK 7 tiene un [Objects.equals] similar (http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals (java.lang.Object,% 20java.lang) .Object)) método. – pesche

4

Project Lombok también tiene un generador de equals y hashCode utilizando la anotación @EqualsAndHashCode que tiene la ventaja de estar en sincronización con el código de clase/fuente de corriente. No estoy seguro de los detalles de la implementación, pero definitivamente vale la pena analizar si necesita reducir el cruft.

1

Una forma más simple (que no sea la generación del código) podría ser.

public boolean equals(Object o) { 
    return o instanceof Id 
     && (name == null ? ((Id)o).name == null : name.equals(((Id)o).name); 
} 
+0

Esto no se generaliza muy bien (al menos en términos de legibilidad). Son solo menos líneas para el caso donde tienes un campo. Mi respuesta todavía se aplica aquí también: 'return o instanceof Id && Objects.equal (name, ((Id) o) .name);' – Tom

+0

@Tom, Su respuesta escalaría mejor, pero requiere una biblioteca adicional (Tengo una método de ayuda para hacer lo mismo;) Creo que esta es la respuesta completa más corta a la pregunta. –

+0

+1: Implementación correcta más corta hasta el momento ((instancia nula del objeto) == falsa). Vale la pena señalar que si el nombre nunca puede ser nulo, esto se puede simplificar aún más. – meriton