I costruttori di commons / lang sono fantastici e li uso da anni senza spese generali evidenti (con e senza ibernazione). Ma come scrive Alain, il modo di Guava è ancora più bello:
Ecco un esempio di fagiolo:
public class Bean{
private String name;
private int length;
private List<Bean> children;
}
Ecco equals () e hashCode () implementati 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;
}
}
e qui con Java 7 o versioni successive (ispirato a 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: questo codice originariamente faceva riferimento a Guava, ma come hanno sottolineato i commenti, da allora questa funzionalità è stata introdotta in JDK, quindi Guava non è più necessaria.
Come puoi vedere, la versione di Guava / JDK è più corta ed evita oggetti helper superflui. In caso di uguaglianza, consente anche di cortocircuitare la valutazione se una Object.equals()
chiamata precedente restituisce false (per essere onesti: commons / lang ha un ObjectUtils.equals(obj1, obj2)
metodo con semantica identica che potrebbe essere usato invece di EqualsBuilder
consentire il cortocircuito come sopra).
Quindi: sì, i costruttori di lang comuni sono molto preferibili rispetto ai metodi equals()
e ai hashCode()
metodi costruiti manualmente (o quei terribili mostri che Eclipse genererà per te), ma le versioni Java 7+ / Guava sono ancora migliori.
E una nota su Hibernate:
fai attenzione a usare raccolte pigre nelle tue implementazioni equals (), hashCode () e toString (). Ciò fallirà miseramente se non hai una sessione aperta.
Nota (about equals ()):
a) in entrambe le versioni di equals () sopra, potresti voler usare anche una o entrambe queste scorciatoie:
@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) a seconda della tua interpretazione del contratto equals (), puoi anche cambiare le righe
if(obj instanceof Bean){
per
// make sure you run a null check before this
if(obj.getClass() == getClass()){
Se usi la seconda versione, probabilmente vorrai anche chiamare il super(equals())
tuo equals()
metodo. Le opinioni differiscono qui, l'argomento è discusso in questa domanda:
modo giusto per incorporare la superclasse in un'implementazione di Guava Objects.hashcode ()?
(anche se si tratta hashCode()
, lo stesso vale per equals()
)
Nota (ispirata al commento di kayahr )
Objects.hashCode(..)
(proprio come il sottostante Arrays.hashCode(...)
) potrebbe funzionare male se hai molti campi primitivi. In tali casi, EqualsBuilder
potrebbe effettivamente essere la soluzione migliore.
reflectionEquals
ereflectionHashcode
; la performance è un killer assoluto.