Commons / lang builders - це чудово, і я використовую їх протягом багатьох років, не відчуваючи накладних витрат (із сплячим режимом та без нього). Але, як пише Ален, спосіб Гуави ще приємніший:
Ось зразок Біна:
public class Bean{
private String name;
private int length;
private List<Bean> children;
}
Ось рівні () та hashCode (), реалізовані з 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;
}
}
і ось з Java 7 або новішої версії (натхненний 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;
}
}
Примітка: цей код спочатку посилався на Guava, але, як зазначали коментарі, ця функціональність з тих пір була впроваджена в JDK, тому Guava більше не потрібна.
Як ви бачите, версія Guava / JDK є коротшою і уникає зайвих помічників. У разі рівності він навіть дозволяє проводити оцінку короткого замикання, якщо попередній Object.equals()
виклик повертає помилкове значення (справедливо: commons / lang має ObjectUtils.equals(obj1, obj2)
метод з однаковою семантикою, який можна використовувати замість того, EqualsBuilder
щоб дозволити коротке замикання, як зазначено вище).
Отже: так, спільнокомандуючим спільнокореневим будівництвом дуже зручніше, ніж створені вручну equals()
та hashCode()
методи (або ті жахливі монстри Eclipse генерують для вас), але версії Java 7+ / Guava ще кращі.
І примітка про сплячку:
будьте обережні щодо використання ледачих колекцій у ваших реалізаціях equals (), hashCode () та toString (). Це вийде з ладу, якщо у вас немає відкритої сесії.
Примітка (про рівних ()):
а) в обох версіях рівняння () вище, ви можете також використовувати один або обидва ці ярлики:
@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) залежно від вашого тлумачення договору equals (), ви також можете змінити рядки
if(obj instanceof Bean){
до
// make sure you run a null check before this
if(obj.getClass() == getClass()){
Якщо ви використовуєте другу версію, ви, ймовірно, також захочете зателефонувати super(equals())
всередину свого equals()
методу. Думки тут різняться, тема обговорюється в цьому питанні:
правильний спосіб включити суперклас у реалізацію Guava Objects.hashcode ()?
(хоча це приблизно hashCode()
, те саме стосується equals()
)
Примітка (натхненна коментарем від kayahr )
Objects.hashCode(..)
(так само, як і в основі Arrays.hashCode(...)
), може бути погано, якщо у вас багато примітивних полів. У таких випадках EqualsBuilder
насправді може бути кращим рішенням.
reflectionEquals
таreflectionHashcode
; вистава - абсолютний вбивця.