Компоненты commons / lang великолепны, и я использую их годами без заметного снижения производительности (в спящем режиме и без него). Но, как пишет Ален, путь гуавы еще приятнее:
Вот образец Боба:
public class Bean{
private String name;
private int length;
private List<Bean> children;
}
Вот equals () и 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 или выше (вдохновленный Гуавой):
@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()
вызов возвращает false (справедливо: у commons / lang есть ObjectUtils.equals(obj1, obj2)
метод с идентичной семантикой, который можно использовать вместо того, EqualsBuilder
чтобы разрешить короткое замыкание, как указано выше).
Итак: да, сборщики общего языка более предпочтительны, чем созданные вручную equals()
и hashCode()
методы (или те ужасные монстры, которые Eclipse сгенерирует для вас), но версии Java 7+ / Guava еще лучше.
И заметка о Hibernate:
Будьте осторожны с использованием отложенных коллекций в ваших реализациях equals (), hashCode () и toString (). Это с треском провалится, если у вас нет открытого сеанса.
Примечание (примерно равно ()):
а) в обеих версиях equals (), приведенных выше, вы можете использовать один или оба из этих ярлыков:
@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
б) в зависимости от вашей интерпретации контракта 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
функций; производительность является абсолютным убийцей.