Как перейти с Ломбока на Котлин

Наша команда любит кодить на Kotlin. Фактически, нам это так нравится, что мы конвертируем наши существующие Java-проекты в Kotlin. В большинстве этих Java-проектов используется Lombok. Мы подумали, что это будет хороший эксперимент, чтобы увидеть, сможем ли мы заменить все наши аннотированные Java-классы Lombok идиоматическим кодом Kotlin.

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

@Data и @Value

Нам часто нужны классы, основная цель которых - хранить данные. Эти классы включают написание стандартного кода. Написание шаблонных методов, таких как getters, setters, toString, equals и hashCode, может быть утомительным. Lombok решает эту проблему, предоставляя @Data для изменяемых классов и @Value для неизменяемых классов. Эти аннотации генерируют для вас стандартные методы.

Классы данных

Kotlin признает потребность в классах, основной целью которых является хранение данных, и предоставляет классы данных для решения этой проблемы. Классы данных наследуют стандартные методы из свойств в основном конструкторе. Мы можем использовать ключевые слова var и val для создания изменяемых или неизменяемых классов.

Конкретные стандартные методы

Помимо @Data и @Value, в Lombok есть аннотации для создания определенных шаблонных методов, таких как @Getter, @Setter, @ToString и @EqualsAndHashCode. Котлин менее гибкий. Невозможно создать определенные стандартные методы. Для нас это не проблема, поскольку мы никогда не используем эти аннотации в нашей базе кода.

@Builder

Конструктор - один из наиболее часто используемых шаблонов проектирования в Java. @Builder генерирует весь шаблонный код, используемый для реализации компоновщика. Несмотря на свою популярность, в Котлине меньше необходимости в шаблоне-строителе. Это связано с тем, что Kotlin поддерживает аргументы по умолчанию и именованные аргументы.

Аргументы по умолчанию и именованные аргументы

Kotlin допускает значения по умолчанию для параметров функции. Если вы укажете значение по умолчанию, вы можете опустить этот аргумент при вызове функции. Kotlin также позволяет именовать аргументы в вызовах функций. Именованные аргументы позволяют предоставлять аргументы в любом порядке.

Шаблон строителя не бесполезен

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

@NonNull

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

Противоположности

Котлин и Ломбок - противоположности. В Lombok вы объявляете поля, не допускающие значения NULL, в Kotlin вы объявляете поля, допускающие значение NULL. Мне подход Котлина кажется более логичным, поскольку поля чаще не допускают значения NULL, чем значения NULL.

@С участием

Чтобы обновить поля в неизменяемых классах, вы клонируете класс с новым значением для поля, которое хотите изменить. Lombok предоставляет @With для создания withFieldName(newValue) методов. Эти методы создают клон с новым значением для связанного поля.

Копировать

Классы данных поддерживают клонирование "из коробки", предоставляя функцию copy(). Именованные аргументы позволяют устанавливать новые значения для нескольких полей с помощью этой единственной функции.

Копия включает все поля

Между @With и copy() есть два ключевых различия. Установив @With на уровне класса или поля, вы можете создать withFieldName(newValue) методы для определенных полей. Функция copy() всегда включает все поля. Другое отличие состоит в том, что copy() позволяет устанавливать несколько полей одновременно, тогда как @With позволяет обновлять несколько полей только путем объединения withFieldName(newValue) методов.

@Cleanup

Lombok генерирует конструкцию try / finally для очистки объявлений локальных переменных, помеченных @Cleanup в конце вашей текущей области.

Использовать

use является частью стандартной библиотеки Kotlin. Он выполняет функцию блока для ресурса и закрывает его за вас. Ресурс закрывается, даже если функция вызывает исключение.

@SneakyThrows

@SneakyThrows Lombok позволяет генерировать проверенные исключения, не объявляя их в предложении throws вашего метода. В Kotlin нет отмеченных исключений, поэтому в этой аннотации нет необходимости. Официальная документация объясняет, почему в Kotlin нет проверенных исключений.

@Бревно

Lombok предоставляет множество вариантов этой аннотации. Какой из них вы будете использовать, зависит от выбранной структуры ведения журнала. Аннотируя ваш класс с помощью @Slf4J, Lombok инициализирует регистратор Slf4J в статическом финальном поле log.

Фреймворк Kotlin-logging

Kotlin не имеет встроенной альтернативы для @Log. Это означает, что мы должны выполнить инициализацию самостоятельно. Фреймворк ведения журнала, который хорошо работает с Kotlin, называется kotlin-logging. Это Slf4J оболочка с лучшей поддержкой Kotlin.

Последовательность - ключ к успеху

Я считаю, что основная цель @Log Lombok не в том, чтобы избавить вас от написания единственной строчки кода для инициализации регистратора, а в том, чтобы инициализировать регистраторы единообразно. Большинству средств ведения журнала при инициализации требуется имя класса. Логгер легко инициализировать с неправильным именем класса из-за ошибок копирования и вставки. Поскольку kotlin-logging не требует имени класса при инициализации, он не подвержен ошибкам копирования и вставки.

Заключение

Иногда подход Kotlin менее гибок. Класс данных всегда будет реализовывать стандартные функции, в то время как Lombok дает вам возможность создать определенный шаблонный метод. В других областях Kotlin более мощный. Например, copy() позволяет вам установить несколько полей за один вызов. Чтобы сделать такие же модификации с @With Lombok, вам нужно клонировать объект несколько раз.

Незначительные различия между аннотациями Lombok и альтернативами Kotlin могут означать, что вам нецелесообразно избавляться от Lombok. Для нас различия не проблема. В конце концов, мы могли без проблем заменить аннотации Lombok идиоматическим кодом Kotlin во всех наших проектах.

Спасибо за прочтение. Я надеюсь, что это было полезно. Если у вас есть вопросы или отзывы, не стесняйтесь оставлять ответ.