Утилита Lombok

  • Рубрика записи:Spring back-end

Java – отличный язык. Однако порой приходится писать много шаблонного кода. Всякие геттеры и сеттеры для каждого поля, конструкторы, переопределение методов toString(), equals() или hashCode(), создание builder-ов для классов… А что, если я скажу, что можно проще?

Lombok – это проект, который позволяет при помощи аннотаций кратко и лаконично делать всё вышеперечисленное, и даже больше. Вы скажете – почему бы не воспользоваться генерацией кода средой разработки? Всё просто – проблема не только в написании шаблонного кода, но и в его чтении. Когда ваш класс на 80% забит шаблонным кодом, приходится каждый раз тратить силы на поиски нужных методов. При использовании Lombok вы видите только то, что действительно важно.

Библиотеку Lombok можно использовать не только в проектах Spring. Однако я подумала, что он отлично подходит для разбора в теме Spring Framework, так как делает сущности ещё более понятными и лаконичными. Объединяя Spring и Lombok, мы приходим к коду, где повторение однотипных конструкций сводится к минимуму.

Добавление зависимости

Для того, чтобы использовать библиотеку Lombok в своём проекте, нужно включить её в файл сборки Maven pom.xml с помощью следующего кода:

В целом, после нажатия на кнопку синхронизации плагина Maven, на этом можно закончить подключение зависимости. Однако мы имеем дело с библиотекой, которая завязана на аннотациях. Maven, как правило, автоматически сканирует classpath и успешно находит обработчики аннотаций. Однако мне больше нравится быть точно уверенной, что библиотеки смогут обрабатывать аннотации. Поэтому я указываю это явным образом. В коде ниже указано, что 2 библиотеки должны уметь обрабатывать аннотации: это Spring и Lombok. В будущем к ним добавится третья, MapStruct. Но это уже совсем другая история.

Возможности Lombok

После добавления зависимости можно начинать творить удивительные вещи. И эти вещи не будут загромождать код, что очень важно.

Геттеры и сеттеры

Если поставить аннотацию @Getter или @Setter перед полем – Lombok автоматически создаст для него геттер или сеттер соответственно. По умолчанию это публичные методы, однако вы можете изменить уровень доступа, задав параметр AccessLevel.

Аннотации @Getter и @Setter также можно применить ко всему классу целиком. В таком случае геттеры и сеттеры создадутся для всех его полей. Например, для поля с именем name будут созданы методы getName() и setName(). Однако, если поле имеет тип boolean (например, boolean ready), геттер будет называться isReady().

Теперь попробуем где-нибудь создать экземпляр класса IceCream. Поставив после имени объекта точку, видим, что среда разработки подсказывает 6 методов из этого класса. Всё это – геттеры и сеттеры, автоматически созданные библиотекой Lombok. И мы можем их использовать сразу, как пометили класс аннотациями @Getter и @Setter. Это круто. Но это не предел возможностей этой библиотеки.

Просмотр геттеров и сеттеров, автоматически сгенерированных утилитой Lombok

Конструкторы

Аннотации @NoArgsConstructor, @RequiredArgsConstructor и @AllArgsConstructor в библиотеке Lombok предоставляют удобные способы автоматической генерации конструкторов в классах.

@NoArgsConstructor генерирует конструктор без аргументов (пустой конструктор). @RequiredArgsConstructor генерирует конструктор, принимающий аргументы для всех final и @NonNull полей класса. @AllArgsConstructor генерирует конструктор, принимающий аргументы для всех полей класса.

Попробуем использовать вместе аннотации @AllArgsConstructor и @NoArgsConstructor:

Просмотр конструкторов, автоматически сгенерированных утилитой Lombok

Благодаря двум аннотациям можно воспользоваться двумя конструкторами. Первый принимает 3 аргумента для 3 полей класса. Второй не принимает никаких аргументов.

При использовании @RequiredArgsConstructor в конструктор попадут только те поля, которые обязательно нужно заполнить значением в конструкторе. Например, final-поля:

Только поле String name было помечено как final. Поэтому только это поле попало в конструктор, генерируемый аннотацией @RequiredArgsConstructor.

Просмотр конструктора, автоматически сгенерированного утилитой Lombok

ToString

Чтобы не переопределять метод toString() вручную, вы можете пометить свой класс аннотацией @ToString. Оставлю аннотацию @AllArgsConstructor, чтобы продемонстрировать @ToString на примере созданных объектов. Вот как это работает:

Вывод в консоль результата метода toString(), автоматически сгенерированного утилитой Lombok

Сгенерированный метод toString() включает в себя имена и значения всех полей класса. При выводе результата в консоль можно в этом убедиться (поля name и ballCount были отражены в полученной строке).

Однако не всегда нужно включать все поля в генерируемый toString(). Обозначить поле как исключаемое из генерации toString() можно так:

А можно это сделать и вот так:

В обоих случаях результат один. Строка, создаваемая методом toString(), будет включать все поля, кроме ready. Но как именно прописывать это в коде – на ваше усмотрение.

Вывод в консоль результата метода toString(), автоматически сгенерированного утилитой Lombok с указанием Exclude

Equals и HashCode

Lombok автоматически создаст за вас методы equals() и hashCode(). Просто пометьте ваш класс аннотацией @EqualsAndHashCode.

Если же вы хотите исключить какие-либо поля из сравнения и расчёта хеша, вы можете поступить так же, как с аннотацией @ToString. Можно сделать вот так:

Или вот так:

Data

Аннотация @Data – это очень неплохой ход. Ведь она заменяет собой совокупность аннотаций @Getter, @Setter, @ToString, @EqualsAndHashCode и @RequiredArgsConstructor. Они часто пригождаются вместе, и потому вам не придётся писать над каждым классом по 5 аннотаций. Достаточно просто написать @Data.

Следующие 2 примера кода идентичны по своему действию.

Builder

Очень крутая аннотация @Builder. Она позволяет генерировать класс-строитель внутри вашего класса для удобного создания объектов при большом количестве полей.

Просмотр класса-строителя builder, автоматически сгенерированного утилитой Lombok

Теперь для создания нового объекта класса IceCream нужно обратиться к самому классу IceCream и получить класс-строитель при помощи статического метода builder(). После этого можно заполнять поля друг за другом. А в конце нужно собрать объект IceCream, вызвав метод build().

Этих аннотаций хватает с головой, чтобы убирать 90% типового кода. Если вам интересно ещё больше – милости прошу в официальную документацию Lombok.

Что под капотом

Интересно же посмотреть, что там нагенерировал Lombok? Именно этим мы сейчас и займёмся. Смотреть будем вот на этот класс:

Чтобы увидеть своими глазами этот код, нужно собрать проект (Build -> Build Project). После сборки можно тихонечко заглянуть в дерево проекта. Найдём там папку target. В ней хранятся сгенерированные классы и другие прикольные штучки. Из папки classes перейдём по разным другим папкам и доберёмся наконец до заветного класса IceCream. Это то, что нужно. Теперь будем пристально рассматривать код, который создал Lombok по двум аннотациям – @Data и @Builder.

Поиск класса IceCream, сгенерированного автоматически утилитой Lombok

Да, какие-то непонятные доллары $ в названиях переменных и var10000 в toString(). Вообще не содержательные имена. А также большие уровни вложенности в equals(). Однако Lombok всё сделал по-честному.

Что ж, при использовании утилиты Lombok объём кода сильно сокращается, а читаемость – повышается. Это ли не чудо? И, конечно же, время, которое тратит разработчик на прописывание шаблонного кода, можно направить в другое русло. Например, на обдумывание логичной структуры программы в парадигме ООП.

Занимательный факт: Lombok – это тоже остров, как и Java, и находятся они совсем недалеко друг от друга.

Острова Java и Lombok рядом на карте

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