Estou curioso para saber, o que as pessoas aqui pensam sobre o uso de
org.apache.commons.lang.builder
EqualsBuilder
/ HashCodeBuilder
para implementar o equals
/ hashCode
? Seria uma prática melhor do que escrever a sua própria? Toca bem com o Hibernate? Qual a sua opinião?
155
reflectionEquals
ereflectionHashcode
; o desempenho é um assassino absoluto.Respostas:
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:
Aqui estão equals () e hashCode () implementados com o Commons / Lang:
e aqui com Java 7 ou superior (inspirado no Guava):
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 umObjectUtils.equals(obj1, obj2)
método com semântica idêntica que poderia ser usada em vez deEqualsBuilder
permitir um curto-circuito como acima).Então: sim, os commons lang builders são muito preferíveis aos métodos
equals()
ehashCode()
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:
b) dependendo da sua interpretação do contrato equals (), você também pode alterar a (s) linha (s)
para
Se você usa a segunda versão, provavelmente também deseja chamar
super(equals())
dentro do seuequals()
método. As opiniões diferem aqui, o tópico é discutido nesta pergunta:(embora seja sobre
hashCode()
, o mesmo se aplica aequals()
)Nota (inspirada em Comentário de kayahr )
Objects.hashCode(..)
(assim como o subjacenteArrays.hashCode(...)
) pode ter um desempenho ruim se você tiver muitos campos primitivos. Nesses casos,EqualsBuilder
pode realmente ser a melhor solução.fonte
equals
. A goiaba converte todos os valores em objetos, o commons-lang cria apenas um único novo objeto.Gente, acorde! Desde o Java 7, existem métodos auxiliares para iguais e hashCode na biblioteca padrão. Seu uso é totalmente equivalente ao uso de métodos Guava.
fonte
Se você não deseja depender de uma biblioteca de terceiros (talvez esteja executando um dispositivo com recursos limitados) e nem mesmo deseja digitar seus próprios métodos, também pode permitir que o IDE faça o trabalho, por exemplo, no uso de eclipse
Você receberá um código 'nativo', que poderá ser configurado como desejar e que deverá ser suportado nas alterações.
Exemplo (eclipse Juno):
fonte
equals
. Se você não quiser depender da biblioteca de terceiros, escreva o método de uma linha comoObjects.equal
você. Mesmo quando usado apenas uma ou duas vezes, torna o código muito melhor!equals
/hashCode
métodos de uma linha ???O EqualsBuilder e o HashCodeBuilder têm dois aspectos principais diferentes do código escrito manualmente:
O EqualsBuilder e o HashCodeBuilder facilitam a comparação de campos que poderiam ser nulos. Com o código gravado manualmente, isso cria muitos clichês.
O EqualsBuilder, por outro lado, criará uma instância por chamada de método igual. Se seus métodos iguais forem chamados com frequência, isso criará muitas instâncias.
Para o Hibernate, a implementação equals e hashCode não faz diferença. Eles são apenas um detalhe de implementação. Para quase todos os objetos de domínio carregados com hibernação, a sobrecarga de tempo de execução (mesmo sem análise de escape) do Builder pode ser ignorada . A sobrecarga do banco de dados e da comunicação será significativa.
Como skaffman mencionou, a versão de reflexão não pode ser usada no código de produção. A reflexão será lenta e a "implementação" não estará correta para todas, exceto as classes mais simples. Levar todos os membros em consideração também é perigoso, pois os membros recém-introduzidos alteram o comportamento do método igual. A versão de reflexão pode ser útil no código de teste.
fonte
Se você não quiser escrever, também há a possibilidade de usar o google guava (anteriormente coleções do Google)
fonte
Se você está apenas lidando com o bean de entidade em que id é uma chave primária, você pode simplificar.
fonte
Na minha opinião, ele não funciona bem com o Hibernate, especialmente os exemplos da resposta que compara comprimento, nome e filhos para alguma entidade. O Hibernate recomenda usar a chave comercial para ser usada em equals () e hashCode (), e eles têm seus motivos. Se você usar o gerador automático equals () e hashCode () em sua chave comercial, tudo bem, apenas os problemas de desempenho precisam ser considerados como mencionado anteriormente. Mas as pessoas geralmente usam todas as propriedades, o que está muito errado na IMO. Por exemplo, atualmente estou trabalhando em um projeto em que as entidades são escritas usando Pojomatic com @AutoProperty, o que considero um padrão realmente ruim.
Seus dois cenários principais para usar hashCode () e equals () são:
Então, vamos assumir que nossa entidade se parece com isso:
Ambas são a mesma entidade para o Hibernate, que foram buscadas em alguma sessão em algum momento (seu ID e classe / tabela são iguais). Mas quando implementamos auto equals () um hashCode () em todos os objetos, o que temos?
Portanto, para o projeto de 99% que faço, usamos a seguinte implementação de equals () e hashCode () escritos uma vez na classe de entidade base, o que é consistente com os conceitos do Hibernate:
Para a entidade transitória, faço o mesmo que o Hibernate fará no passo de persistência, ie. Eu uso a correspondência de instância. Para os objetos persistentes, comparo a chave exclusiva, que é a tabela / ID (nunca uso chaves compostas).
fonte
Caso outras pessoas achem útil, eu criei essa classe Helper para o cálculo do código de hash que evita a sobrecarga adicional de criação de objeto mencionada acima (na verdade, a sobrecarga do método Objects.hash () é ainda maior quando você tem herança, pois criará uma nova matriz em cada nível!).
Exemplo de uso:
O auxiliar HashCode:
Imaginei que 10 é o número máximo razoável de propriedades em um modelo de domínio; se você tiver mais, pense em refatorar e introduzir mais classe em vez de manter um monte de Strings e primitivas.
As desvantagens são: não é útil se você tiver principalmente primitivos e / ou matrizes que você precisa fazer hash profundo. (Normalmente, esse é o caso quando você precisa lidar com objetos simples (transferência) que estão fora de seu controle).
fonte