Los creadores de commons / lang son geniales y los he estado usando durante años sin sobrecarga de rendimiento notable (con y sin hibernación). Pero como Alain escribe, la forma de la guayaba es aún mejor:
Aquí hay una muestra de Bean:
public class Bean{
private String name;
private int length;
private List<Bean> children;
}
Aquí está equals () y hashCode () implementado con Commons / Lang:
@Override
public int hashCode(){
return new HashCodeBuilder()
.append(name)
.append(length)
.append(children)
.toHashCode();
}
@Override
public boolean equals(final Object obj){
if(obj instanceof Bean){
final Bean other = (Bean) obj;
return new EqualsBuilder()
.append(name, other.name)
.append(length, other.length)
.append(children, other.children)
.isEquals();
} else{
return false;
}
}
y aquí con Java 7 o superior (inspirado en Guava):
@Override
public int hashCode(){
return Objects.hash(name, length, children);
}
@Override
public boolean equals(final Object obj){
if(obj instanceof Bean){
final Bean other = (Bean) obj;
return Objects.equals(name, other.name)
&& length == other.length // special handling for primitives
&& Objects.equals(children, other.children);
} else{
return false;
}
}
Nota: este código originalmente hacía referencia a Guava, pero como los comentarios han señalado, esta funcionalidad se ha introducido en el JDK, por lo que Guava ya no es necesaria.
Como puede ver, la versión Guava / JDK es más corta y evita objetos auxiliares superfluos. En caso de igual, incluso permite un cortocircuito en la evaluación si una Object.equals()
llamada anterior devuelve falso (para ser justos: commons / lang tiene un ObjectUtils.equals(obj1, obj2)
método con semántica idéntica que podría usarse en lugar de EqualsBuilder
permitir un cortocircuito como se indicó anteriormente).
Entonces: sí, los constructores de lang comunes son muy preferibles a los métodos equals()
y hashCode()
métodos construidos manualmente (o esos monstruos horribles que Eclipse generará para usted), pero las versiones de Java 7+ / Guava son aún mejores.
Y una nota sobre Hibernate:
tenga cuidado con el uso de colecciones diferidas en sus implementaciones equals (), hashCode () y toString (). Eso fallará miserablemente si no tiene una sesión abierta.
Nota (sobre equals ()):
a) en ambas versiones de equals () anteriores, es posible que desee utilizar uno o ambos de estos atajos también:
@Override
public boolean equals(final Object obj){
if(obj == this) return true; // test for reference equality
if(obj == null) return false; // test for null
// continue as above
b) dependiendo de su interpretación del contrato equals (), también puede cambiar la (s) línea (s)
if(obj instanceof Bean){
a
// make sure you run a null check before this
if(obj.getClass() == getClass()){
Si usa la segunda versión, probablemente también desee llamar super(equals())
dentro de su equals()
método. Las opiniones difieren aquí, el tema se discute en esta pregunta:
forma correcta de incorporar superclase en una implementación de Guava Objects.hashcode ()?
(aunque se trata hashCode()
, lo mismo se aplica a equals()
)
Nota (inspirada en el comentario de kayahr )
Objects.hashCode(..)
(al igual que el subyacente Arrays.hashCode(...)
) podría funcionar mal si tiene muchos campos primitivos. En tales casos, en EqualsBuilder
realidad puede ser la mejor solución.
reflectionEquals
yreflectionHashcode
; El rendimiento es un asesino absoluto.