You've successfully subscribed to Заметки Разработчиков
Great! Next, complete checkout for full access to Заметки Разработчиков
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info is updated.
Billing info update failed.

best-practices

Не используйте @Data

Многие разработчики в принципе против использования Lombok. В общем, это холиварная тема. Но вы используете Lombok в проекте, то не используйте хотя бы спорные и откровенно вредные аннотации.

Многие разработчики в принципе против использования Lombok. В общем, это холиварная тема. Но вы используете Lombok в проекте, то не используйте хотя бы спорные и откровенно вредные аннотации.

Одна из таких – это @Data. Во-первых, мало кто помнит, что она под собой скрывает.

  • @ToString. Не помню, когда последний раз переопределял toString(). А если объект содержит чувствительную информацию?
  • @EqualsAndHashCode. Это самая вредная аннотация в @Data. Потому что она генерирует equals() и hashCode() по всем полям. Обычно вы не хотите, чтобы генерация осуществлялась по всем полям. Например, для сущности достаточно идентификатора.
  • @Getter / @Setter. Здесь ничего плохого.
  • @RequiredArgsConstructor. Тоже окей.

Основная проблема в @EqualsAndHashCode. Можно, конечно, использовать @EqualsAndHashCode.Exclude. Эта аннотация запрещает использовать поле при генерации, но вы хотите расставлять это над почти всеми полями в сущности? Потому что @EqualsAndHashCode.Include просто не сработает, нельзя объявить только нужные поля, нужно будет именно исключать все ненужные.

Также избегайте всех аннотаций из пакета experemental. Все аннотации из этого пакета могут работать не стабильно, и при этом могут быть удалены из следующих версий. Исключением из этого пакета является @FieldNameConstants, за пару лет с ней не было никаких проблем, а все имеющиеся альтернативы не очень.

С Lombok код выглядит чище, но, как и в случае с любым другим магическим инструментом, важно понимать, как именно он работает и когда его использовать. В противном случае производительность приложения может снизиться, либо оно вовсе может перестать работать корректно.

Lombok + JPA: Что может пойти не так?
Lombok — это отличный инструмент, с которым Java-код становится чище и лаконичнее. Однако есть несколько нюансов, которые надо учитывать при его использовании с JPA. В этой статье мы выясним, как...
Дополнительная статья на эту тему

Сравнение enum в Java

Enum это объект, как и все в Java. Однако это особенный объект. Каждый из объектов енума создаётся только единожды. Давайте на примере: enum TestEnum {ONE, TWO, THREE} Если мы создадим 10 переменных TestEnum.ONE, то все они будут ссылаться на один и тот же объект. И поэтому enum можно сравнивать

Enum это объект, как и все в Java. Однако это особенный объект. Каждый из объектов енума создаётся только единожды. Давайте на примере:

enum TestEnum {ONE, TWO, THREE}

Если мы создадим 10 переменных TestEnum.ONE, то все они будут ссылаться на один и тот же объект. И поэтому enum можно сравнивать с помощью == и это корректно и будет работать.

Сторонники такого подхода называют следующие преимущества. Давайте их разберем.

Вы никогда не получите NullPointerException. И это правда, но если вы будете придерживаться правила "Сравнение константы слева", то и при использовании .equals() NullPointerException вам не страшен.

Оператор == работает быстрее. Быстрее чего? Видимо метода .equals(). Давайте посмотрим реализацию метода .equals() у enum.

Оператор == более понятный синтаксически. Это еще почему? Для сравнения объектов в Java используется .equals(). Enum это объект. Логичнее и очевиднее использовать .equals() для сравнения, чтобы не нарушать единообразие сравнения объектов.

На мой взгляд, правильнее использовать .equals(), главное не забывать о правиле "Сравнение константы слева".

Сравнение константы слева

Представьте, что у вас есть enum, который отвечает за статус пользователя в системе: "онлайн", "офлайн" и "занят". public enum UserStatus { ONLINE, OFFLINE, BUSY } public class User { ... @Column(name = "status") @Enumerated(EnumType.STRING) private UserStatus status; ... } Скорее всего для выполнения бизнес-логики вам потребуется проверять статус пользователя. if (user.getStatus().equals(UserStatus.

Представьте, что у вас есть enum, который отвечает за статус пользователя в системе: "онлайн", "офлайн" и "занят".

public enum UserStatus {

    ONLINE, OFFLINE, BUSY
    
}
public class User {

    ...

    @Column(name = "status")
    @Enumerated(EnumType.STRING)
    private UserStatus status;
    
    ...

}

Скорее всего для выполнения бизнес-логики вам потребуется проверять статус пользователя.

if (user.getStatus().equals(UserStatus.ONLINE)) {
    // to do something
}

Вроде бы все отлично, миссия выполнена. Но есть одно НО. Что если getStatus() вернет вам null? Правильно, вы получите NullPointerException.

Чтобы этого избежать следует придерживаться правила "Сравнения константы слева". Оно очень простое. В нашем примере, мы точно уверены, что UserStatus.ONLINE существует, поэтому .equals() стоит вызывать от него.

if (UserStatus.ONLINE.equals(user.getStatus())) {
    // to do something
}

В остальных подобных ситуациях делайте также, например со строками:

if ("Иванов".equals(user.getLastName())) {
    // to do something
}

Это простое правило защитит вас от NullPointerException.