Os construtores comuns / lang são ótimos e eu os uso há anos sem sobrecarga perceptível de desempenho (com e sem hibernação). Mas, como Alain escreve, o caminho da goiaba é ainda melhor:
Aqui está uma amostra de Bean:
public class Bean{
private String name;
private int length;
private List<Bean> children;
}
Aqui estão equals () e hashCode () implementados com o 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;
}
}
e aqui com Java 7 ou superior (inspirado no 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 referenciou o Guava originalmente, mas, como os comentários apontaram, essa funcionalidade foi introduzida no JDK; portanto, o Guava não é mais necessário.
Como você pode ver, a versão do Guava / JDK é mais curta e evita objetos auxiliares supérfluos. No caso de iguais, ele permite até um curto-circuito na avaliação se uma Object.equals()
chamada anterior retornar falsa (para ser justo: commons / lang tem um ObjectUtils.equals(obj1, obj2)
método com semântica idêntica que poderia ser usada em vez de EqualsBuilder
permitir um curto-circuito como acima).
Então: sim, os commons lang builders são muito preferíveis aos métodos equals()
e hashCode()
métodos construídos manualmente (ou esses monstros horríveis que o Eclipse irá gerar para você), mas as versões Java 7+ / Guava são ainda melhores.
E uma observação sobre o Hibernate:
tenha cuidado ao usar coleções lentas em suas implementações equals (), hashCode () e toString (). Isso falhará miseravelmente se você não tiver uma sessão aberta.
Nota (sobre igual a ()):
a) nas duas versões de equals () acima, convém usar um ou ambos os atalhos também:
@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) dependendo da sua interpretação do contrato equals (), você também pode alterar a (s) linha (s)
if(obj instanceof Bean){
para
// make sure you run a null check before this
if(obj.getClass() == getClass()){
Se você usa a segunda versão, provavelmente também deseja chamar super(equals())
dentro do seu equals()
método. As opiniões diferem aqui, o tópico é discutido nesta pergunta:
maneira correta de incorporar a superclasse em uma implementação do Guava Objects.hashcode ()?
(embora seja sobre hashCode()
, o mesmo se aplica a equals()
)
Nota (inspirada em Comentário de kayahr )
Objects.hashCode(..)
(assim como o subjacente Arrays.hashCode(...)
) pode ter um desempenho ruim se você tiver muitos campos primitivos. Nesses casos, EqualsBuilder
pode realmente ser a melhor solução.
reflectionEquals
ereflectionHashcode
; o desempenho é um assassino absoluto.