Как перейти с Ломбока на Котлин
Наша команда любит кодить на 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 во всех наших проектах.
Спасибо за прочтение. Я надеюсь, что это было полезно. Если у вас есть вопросы или отзывы, не стесняйтесь оставлять ответ.