Мне любопытно узнать, что люди здесь думают об использовании
org.apache.commons.lang.builder
EqualsBuilder
/ HashCodeBuilder
для реализации equals
/ hashCode
? Будет ли это лучше, чем писать свои собственные? Хорошо ли играет с Hibernate? Каково ваше мнение?
155
reflectionEquals
иreflectionHashcode
функций; производительность является абсолютным убийцей.Ответы:
Компоненты commons / lang великолепны, и я использую их годами без заметного снижения производительности (в спящем режиме и без него). Но, как пишет Ален, путь гуавы еще приятнее:
Вот образец Боба:
Вот equals () и hashCode (), реализованные с помощью Commons / Lang:
и здесь с Java 7 или выше (вдохновленный Гуавой):
Примечание: этот код изначально ссылался на 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 (), приведенных выше, вы можете использовать один или оба из этих ярлыков:
б) в зависимости от вашей интерпретации контракта equals (), вы также можете изменить строку (и)
в
Если вы используете вторую версию, вы, вероятно, также захотите вызвать
super(equals())
внутри вашегоequals()
метода. Здесь мнения расходятся, тема обсуждается в этом вопросе:(хотя это примерно
hashCode()
то же самое относится и кequals()
)Примечание (вдохновлено комментарием от kayahr )
Objects.hashCode(..)
(так же, как базовыйArrays.hashCode(...)
) может работать плохо, если у вас много примитивных полей. В таких случаях, наEqualsBuilder
самом деле , может быть лучшим решением.источник
equals
. Guava преобразует все значения в объекты, commons-lang создает только один новый объект.Люди, проснись! Начиная с Java 7 в стандартной библиотеке есть вспомогательные методы для equals и hashCode . Их использование полностью эквивалентно использованию методов Guava.
источник
Если вы не хотите зависеть от сторонней библиотеки (возможно, вы используете устройство с ограниченными ресурсами) и даже не хотите вводить свои собственные методы, вы также можете позволить среде IDE выполнять свою работу, например, при использовании Eclipse.
Вы получите «нативный» код, который вы можете настроить по своему усмотрению и который вы должны поддерживать при изменениях.
Пример (затмение Юнона):
источник
equals
. Если вы не хотите зависеть от сторонней библиотеки, напишите такой же однострочный метод, как иObjects.equal
вы. Даже если он используется только один или два раза, он делает код лучше!equals
/hashCode
однострочные методы ???EqualsBuilder и HashCodeBuilder имеют два основных аспекта, которые отличаются от написанного вручную кода:
EqualsBuilder и HashCodeBuilder упрощают сравнение полей, которые могут быть нулевыми. С помощью написанного вручную кода это создает много шаблонов.
EqualsBuilder, с другой стороны, создаст экземпляр для вызова метода equals. Если ваши методы equals вызывают часто, это создаст много экземпляров.
Для Hibernate реализация equals и hashCode не имеет значения. Они просто деталь реализации. Почти для всех доменных объектов, загруженных с помощью hibernate, издержки времени исполнения (даже без анализа escape) Builder можно игнорировать . Затраты на базу данных и связь будут значительными.
Как отметил Скаффман, версия отражения не может быть использована в рабочем коде. Отражение будет медленным, и «реализация» будет правильной не для всех, кроме самых простых классов. Учет всех членов также опасен, так как новые участники изменяют поведение метода equals. Версия отражения может быть полезна в тестовом коде.
источник
Если вы не пишете свой собственный, есть также возможность использовать Google Guava (ранее коллекции Google)
источник
Если вы просто имеете дело с бином сущности, где id является первичным ключом, вы можете упростить.
источник
На мой взгляд, это плохо сочетается с Hibernate, особенно в примерах из ответа, сравнивающих длину, имя и детей для некоторой сущности. Hibernate рекомендует использовать бизнес-ключ для использования в equals () и hashCode (), и у них есть свои причины. Если вы используете генератор auto equals () и hashCode () для своего бизнес-ключа, это нормально, только проблемы с производительностью необходимо учитывать, как упоминалось ранее. Но люди обычно используют все свойства, что IMO очень неправильно. Например, я сейчас работаю над проектом, в котором сущности пишутся с использованием Pojomatic с @AutoProperty, что я считаю очень плохим паттерном.
Два основных сценария использования hashCode () и equals ():
Итак, давайте предположим, что наша сущность выглядит так:
Оба являются одним и тем же объектом для Hibernate, который был извлечен из некоторого сеанса в определенный момент (их id и класс / таблица равны). Но когда мы реализуем auto equals () hashCode () на всех объектах, что мы имеем?
Итак, для 99% проекта, который я делаю, мы используем следующую реализацию equals () и hashCode (), написанную один раз в базовом классе сущности, что согласуется с концепциями Hibernate:
Для переходной сущности я делаю то же самое, что и Hibernate на шаге персистентности, т.е. Я использую экземпляр матча. Для постоянных объектов я сравниваю уникальный ключ, который является таблицей / идентификатором (я никогда не использую составные ключи).
источник
На всякий случай, другие сочтут это полезным, я придумал этот класс Helper для вычисления хеш-кода, который позволяет избежать дополнительных затрат на создание объекта, упомянутых выше (на самом деле, издержки метода Objects.hash () еще больше, когда у вас есть наследование, поскольку это создаст новый массив на каждом уровне!).
Пример использования:
Помощник HashCode:
Я полагал, что 10 - это максимально разумное количество свойств в доменной модели, если у вас есть больше, вы должны подумать о рефакторинге и введении большего количества классов, вместо того, чтобы поддерживать кучу строк и примитивов.
Недостатки: бесполезно, если у вас есть в основном примитивы и / или массивы, которые нужно глубоко хэшировать. (Обычно это тот случай, когда вам приходится иметь дело с плоскими (переносными) объектами, которые находятся вне вашего контроля).
источник