Lombok @EqualsAndHashCode — облегчаем сравнение объектов

Цикл статей «Project Lombok».

Следующая статья — «Lombok @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor».
Предыдущая статья — «Lombok @ToString».

К любому объявлению класса может быть применена аннотация @EqualsAndHashCode, чтобы lombok сгенерировал методы equals(Object other) и hashCode(). По умолчанию используются все нестатические, не-transient поля, но вы можете исключить некоторые поля, перечислив их в параметре exclude. Или вы можете явно указать, какие поля вы хотите использовать, перечислив их в параметре of.

Если @EqualsAndHashCode применяется к классу, который расширяет другой класс, то эта возможность становится более сложной.  Обычно автогенерируемые методы equals и hashCode для этих классов являются плохой идеей, так как родительский класс тоже определяет поля, которые тоже нужно использовать в equals и hashCode, но они НЕ используются. Устанавливая callSuper в true, вы можете включить методы equals и hashCode суперкласса в сгенерированные методы.  Для hashCode вставляется вызов super.hashCode() в алгоритм вычисления, а для equals сгенерированный метод возвращает false, если реализация метода в родительском классе решит, что объект не равен переданному. Имейте в виду, что не все реализации equals обрабатывают эту ситуацию правильно. Однако вы можете без опасений вызвать метод родительского класса, если этот метод тоже сгенерирован lombok. Если вы имеете определённый родительский класс, который вам нужно поддерживать, то укажите callSuper, чтобы показать, что вы рассмотрели его, иначе выйдет предупреждение.

Установка callSuper в true, когда вы не хотите расширять что-либо (когда вы наследуетесь от java.lang.Object), вызывает ошибку компиляции, потому что это это меняет поведение сгенерированных equals() и hashCode() на то, что было у этих методов в java.lang.Object, то есть только те же самые объекты будут равны и иметь тот же hashCode. Не установка callSuper в true при расширении другого класса вызовет предупреждение, потому что пока в родительском классе нет полей (важных при сравнении), lombok не может сгенерировать реализацию, которая примет во внимание поля родительского класса. Вам нужно написать свои собственные реализации, либо положиться на возможности callSuper.

Новое в Lombok 0.10: Если ваш класс не final и не наследуется прямо от java.lang.Object, lombok генерирует метод canEqual, который означает, что JPA-прокси всё ещё могут быть равны своему базовому классу, но дочерние классы, добавляющие новые состояния, не ломают соглашение об equals. Если все классы иерархии являются мешаниной из классов scala и lombok, то сравнение будет просто «работать». Если вам нужно написать свои собственные методы equals, то всегда переопределяйте canEqual, если вы поменяли equals и hashCode.

Новое в Lombok 1.14.0: Чтобы добавить аннотации к параметру equals (и если необходимо к canEqual), вы можете использовать onParam=@__({@AnnotationsHere}) .  Но будьте осторожны! Это экпериментальная возможность.

С использованием Lombok

Чистая Java

Поддерживаемые ключи конфигурации

Если установлен в true, то lombok будет обращаться к полям напрямую вместо использования методов получения значений (если есть) при генерации методов equals и hashCode. Параметр аннотации doNotUseGetters, если явно указан, имеет приоритет перед этой настройкой.

 

Lombok будет помечать любое использование @EqualsAndHashCode предупреждением или ошибкой, если настроено.

 

Примечания

Массивы могут быть сравнены/вычислена хеш-функция в глубину, что означает, что массивы, содержащие сами себя генерируют исключение StackOverflowError. Однако это поведение не отличается от ArrayList.

Вы можете спокойно полагать, что реализация hashCode не изменится в следующих версиях lombok, однако гарантия не выдолблена на камне. Если будет значительное улучшение производительности при использовании другого алгоритма вычисления хеша, то это будет изменено в будущей версии.

При сравнении значения NaN у типов float и double рассматриваются как равные друг другу, даже не смотря на то что NaN==NaN возвращает false. То же самое с методом equals в java.lang.Double. Этот необходимо для того чтобы обеспечить равенство при сравнении объекта с точной копией самого себя.

Если уже есть метод с именем hashCode или equals (независимо от типа возвращаемого значения), то методы не генерируются, и возникает предупреждение. Эти два метода должны быть синхронизированы друг с другом, что lombok не может гарантировать до тех пор, пока он не генерирует все эти методы, поэтому вы всегда будете получать предупреждение, если один или оба метода уже существуют. Вы можете пометить любой метод @lombok.experimental.Tolerate, чтобы скрыть их от lombok.

Попытка исключения полей, которые не существуют или уже исключены (потому что они статические или transient), приводит к предупреждениям на этих полях. По этой причине вам не нужно беспокоиться об опечатках.

Наличие одновременно exclude и of генерирует предупреждение. Параметр exclude в этом случае игнорируется.

По умолчанию все переменные, начинающиеся с символа «$», исключаются автоматически. Вы можете их добавить только с помощью параметра of.

Если есть метод получения значения для включаемого поля, то вызывается он вместо прямого доступа к полю. Это поведение может быть изменено: @EqualsAndHashCode(doNotUseGetters = true)

Цикл статей «Project Lombok».

Следующая статья — «Lombok @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor».
Предыдущая статья — «Lombok @ToString».

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *