Konstruktory Common / Lang są świetne i używam ich od lat bez zauważalnego narzutu wydajności (zi bez hibernacji). Ale jak pisze Alain, droga Guava jest jeszcze przyjemniejsza:
Oto przykładowy Bean:
public class Bean{
private String name;
private int length;
private List<Bean> children;
}
Oto equals () i hashCode () zaimplementowane za pomocą 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;
}
}
a tutaj z Javą 7 lub nowszą (inspirowaną Guavą):
@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;
}
}
Uwaga: ten kod pierwotnie odwoływał się do guawy, ale jak zauważyły komentarze, ta funkcjonalność została od tego czasu wprowadzona do JDK, więc guawa nie jest już wymagana.
Jak widać, wersja Guava / JDK jest krótsza i unika zbędnych obiektów pomocniczych. W przypadku równości pozwala nawet na zwarcie oceny, jeśli wcześniejsze Object.equals()
wywołanie zwróci fałsz (żeby być sprawiedliwym: commons / lang ma ObjectUtils.equals(obj1, obj2)
metodę o identycznej semantyce, której można użyć zamiast EqualsBuilder
zezwalać na zwarcie jak powyżej).
A więc: tak, konstruktorzy języka wspólnego są bardziej preferowani niż ręcznie konstruowane equals()
i hashCode()
metody (lub te okropne potwory, które wygeneruje dla ciebie Eclipse), ale wersje Java 7+ / Guava są jeszcze lepsze.
I uwaga o Hibernate:
uważaj na używanie leniwych kolekcji w implementacjach equals (), hashCode () i toString (). To się nie powiedzie, jeśli nie masz otwartej sesji.
Uwaga (o równych ()):
a) w obu wersjach equals () powyżej możesz również chcieć użyć jednego lub obu tych skrótów:
@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) w zależności od Twojej interpretacji umowy equals (), możesz również zmienić linię (y)
if(obj instanceof Bean){
do
// make sure you run a null check before this
if(obj.getClass() == getClass()){
Jeśli używasz drugiej wersji, prawdopodobnie chcesz również wywołać super(equals())
wewnątrz swojej equals()
metody. Zdania są tu różne, temat omawiany jest w tym pytaniu:
właściwy sposób na włączenie superklasy do implementacji Guava Objects.hashcode ()?
(choć o to chodzi hashCode()
, to samo dotyczy equals()
)
Uwaga (inspirowana komentarzem od kayahr )
Objects.hashCode(..)
(podobnie jak podstawa Arrays.hashCode(...)
) może działać źle, jeśli masz wiele pól pierwotnych. W takich przypadkach EqualsBuilder
może faktycznie być lepszym rozwiązaniem.
reflectionEquals
ireflectionHashcode
; występ jest absolutnym zabójcą.