Источник: Nuances of Programming
Привет всем энтузиастам Java! Давайте поговорим о Java и рефакторинге. Как известно, Java остается одним из наиболее популярным языком программирования. В каждом новом релизе добавляется все больше фич, с которыми он превращается в идеальное сочетание элементов объектно-ориентированного и функционального языка с введением лямбда-выражений, стримов и CompletableFuture в Java 8.
Всем нам знакомы Java-бины, они же POJO (plain old java objects, “старые-добрые Java-объекты”), они же DTO (data transfer objects, “объекты передачи данных”). Даже несмотря на то, что в обширном Java-сообществе нет согласия по поводу определений, соответствующих каждому из понятий, все они делают примерно то же самое. Названия разные, концепция одна.
Примечание: в этой статье я буду использовать термин DTO для Java-бинов.
Общие черты DTO:
- Все свойства объекта должны быть приватными.
- Объект должен содержать конструктор no-args.
- Объект должен быть сериализуемым (в большинстве случаев, если только он НЕ предназначен для сетевой передачи).
- Объект должен предоставлять способы извлечения (get) и изменения (set) значений свойств с помощью геттеров и сеттеров.
Подводя итог, DTO — это кастомизируемые типы данных, а вышеописанное соглашение — всего лишь условность, которая не является стандартом Java и паттерном проектирования. Впрочем, в конечном счете, паттерн проектирования— это наилучшая практика, доказавшая свою эффективность в решении реальных задач.
Однако существует одна проблема. Что, если DTO содержит, скажем, десять свойств или больше? Вот как выглядит типичный DTO.
Давайте возьмем в качестве примера Employee_DTO, который содержит базовую информацию о сотруднике:
Десятки геттеров и сеттеров здесь смотрятся не особенно хорошо. Разумеется, это один из примеров плохо читаемого спагетти-кода. Представьте, что у вас есть десятки или даже сотни таких DTO вместе с геттерами и сеттерами для каждого из них. Для решения этой проблемы есть элегантный способ, позволяющий достичь того же самого результата с менее шаблонным кодом.
Вот тут-то на сцену и выходит Lombok. Он предоставляет простые аннотации и помогает избежать всего того шаблонного кода, который можно себе представить относительно DTO.
Как Lombok работает за кадром:
Lombok уменьшает шаблонность посредством аннотаций, которые выполняют преобразование классов во время компиляции. Lombok уже поставляется с приличным набором преобразований, но вы также можете создать свои собственные пользовательские преобразования.
Lombok действует как процессор аннотаций, который играет роль диспетчера, делегирующего функции обработчикам аннотаций Lombok (это то, что мы собираемся создать). Обработчики обнаруживаются с помощью фреймворка под названием SPI. Обработчики аннотаций Lombokобъявляют конкретную аннотацию, которую они обрабатывают. При делегировании полномочий обработчику процессор аннотаций Lombok обеспечивает объект, представляющий абстрактное синтаксическое дерево (AST) аннотируемого узла (например: класс, метод, поле и т. д.). Обработчик аннотаций Lombok может свободно изменять AST, вводя новые узлы: методы, поля и выражения. После этапа обработки аннотаций компилятор будет генерировать байт-код уже из модифицированного AST.
Вкратце, Lombok не генерирует код. Вместо этого он использует неопределенные и недокументированные внутренние вызовы API реализации компилятора для непосредственного изменения абстрактного синтаксического дерева программы в промежутке между чтением исходного кода и выводом скомпилированного байт-кода.
Отставим теорию. Давайте посмотрим, как быстро получится ввести Lombok в наш проект Java. maven—зависимость выглядит так:
И Employee_DTO, проиллюстрированный выше, с Lombok будет выглядеть куда более элегантно и читаемо. Давайте рассмотрим несколько примеров, которые показывают, как можно использовать аннотации Lombok.
- Геттеры и сеттеры Lombok для применения ко всему DTO:
Аннотации @Getter и @Setterприменяются ко всему классу, как показано ниже:
2. Геттеры и сеттеры Lombok для применения избирательно в заданном DTO:
В случае если нам нужны геттеры и сеттеры только для определенных переменных/свойств, мы можем добиться и этого тоже:
3. Lombok для замены конструкторов:
а) Замена конструктора all-args
Иногда раскрывать методы-сеттеры не нужно и от клиента требуется устанавливать значения только через вызов конструктора.
Пример Java DTO с конструктором all-args (без использования Lombok):
После замены конструктора all-args в приведенном выше фрагменте кода аннотацией @AllArgsConstructor он, по существу, сводится к чему-то вроде этого:
б) Замена конструктора no-args
И c заменой конструктора no-args всё точно так же:
в) Добавление спецификаторов доступа к конструкторам
При работе с сериализацией и десериализацией Kryo необходимо иметь конструктор no-args с приватным доступом, и Lombok, к счастью, покрывает в том числе подобные сценарии. Пример того, как мы можем определить спецификаторы доступа для конструкторов:
4. Lombok для генерации методов toString():
Lombok также генерирует метод toString(), по умолчанию учитывая все свойства DTO и сохраняя их порядок:
Результат выглядит так:
Person_DTO(personName=John Smith, personAddress=4th Avenue-LA, phoneNum=1234567890, email=abc@xyz.com)
5. Lombok для генерации методов equals() и hashCode():
@EqualsAndHashCode генерирует реализации методов equals(Object other) и hashCode(). По умолчанию здесь применяются исключительно нестатические, нестационарные поля, однако их можно изменить (и даже указать, что должны использоваться выходные данные тех или иных методов), пометив элементы типа с помощью @EqualsAndHashCode.Include или @EqualsAndHashCode.Exclude. Другими словами, вы можете указать, какие именно поля или методы хотите использовать, пометив их @EqualsAndHashCode.Include и применив @EqualsAndHashCode(onlyExplicitlyIncluded = true).
6. @Data: ярлык для @ToString, @EqualsAndHashCode, @Getter по всем полям, @Setter по всем нефинальным полям и @RequiredArgsConstructor.
@RequiredArgsConstructor генерирует конструктор с одним параметром для каждого поля, требующего специальной обработки. Все неинициализированные поля, помеченные как final, получают параметр, как и любые поля, помеченные @NonNull, которые не были инициализированы там, где они объявлены.
Это то же самое, что и задействовать все аннотации, перечисленные в приведенном ниже фрагменте кода:
В проекте Lombok доступны и другие аннотации/утилиты, которые очень полезны и удобны.
К примеру,@var, @val, @NonNull, @Cleanup, @Value, @Builder — и это еще не все.
Очень легко рефакторить существующий код/проект и вводить туда Lombok со значительно меньшими усилиями и без поломок. Как уже упоминалось ранее, код становится намного чище, проще и элегантнее.
Добавление плагина Lombok в IDE
Примечание: если вы используете Eclipse или IntelliJ, простое добавление зависимости Lombok в pom.xml не всегда срабатывает, и плагин Lombok необходимо добавлять вручную (в зависимости от вашей IDE).
Добавление плагина Lombok в IntelliJ.
- Нажмите Command и клавишу запятой (“⌘” + “,”).
- Найдите “Plugin” в верхнем левом углу окна.
- Переключите вкладку, то есть перейдите в раздел “Marketplace”.
- Найдите “Lombok” и нажмите “Install”.
- Перезапустите Intellij.
Добавление плагина Lombok в Eclypse
- Запустите jar командой java -jar. Откроется пользовательский интерфейс установщика.
- Выбрав элементы установки, нажимаем кнопку Install/Update и выходим из программы установки.
- После установки плагина перезапустите Eclipse и убедитесь, что Lombok настроен правильно.
В некоторых случаях вам, возможно, придется переключиться на публичное подключение wi-fi вашей организации, чтобы иметь возможность искать и устанавливать плагины.
Если вы подключены к VPN, попробуйте отключиться от него и после этого добавить плагин.
Если вышеперечисленные приемы не сработают, измените настройки прокси-сервера в IDE и попробуйте добавить плагин еще раз.
Счастливого рефакторинга!
Читайте также:
Читайте нас в телеграмме и vk
Перевод статьи Shreyas N Mahanthappa: Java-Lombok: Do we need getters and setters?