В предыдущей статье мы рассмотрели, подключить библиотеку Lombok к проекту и как установить плагин в IDE. Сегодня же мы расскажем, как использовать Lombok для уменьшения шаблонного кода при разработке программ.
Как использовать Lombok
При написании кода используются аннотации Lombok. С помощью аннатоций Lombok на этапе компиляции генерирует шаблонный код. С помощью аннотаций Lombok можно генерировать конструкторы классов, геттеры и сеттеры, методы toString, equals и hashCode. Давайте вкратце рассмотрим использование Lombok в работе.
Сеттеры и геттеры
Для генерации сеттеров и геттеров используются аннотации @Setter и @Getter, соответственно. Эти аннотации удобно навесить на POJO класс со множеством полей, дабы не генерировать шаблонный код самому.
@Getter @Setter public class Person { private String firstName; private String secondName; private Address address; }
Здесь мы объявили класс Person с тремя полями и указали аннотации @Getter и @Setter. Если вы правильно подключили Lombok и установили плагин, то он сразу же создаст геттеры и сеттеры. Теперь можно воспользоваться созданными методами:
Person person = new Person(); person.setFirstName("Nicola"); person.setSecondName("Tesla"); person.setAddress(new Address()); System.out.println(person.getFirstName() + " " + person.getSecondName());
Примечание: если вы определите какой-либо геттер или сеттер в классе, то Lombok не будет его трогать при генерации кода. То есть уже определённые методы будут иметь приоритет над вновь создаваемыми. Также для нестатических final полей не будут сгенерированы сеттеры.
import lombok.Getter; import lombok.Setter; @Getter @Setter public class Person { private String firstName; private String secondName; private Address address; }
public class Address { }
public class LombokGetterSetter { public static void main(String[] args) { Person person = new Person(); person.setFirstName("Nicola"); person.setSecondName("Tesla"); person.setAddress(new Address()); System.out.println(person.getFirstName() + " " + person.getSecondName()); } }
Конструкторы
Рутинное написание типовых конструкторов можно поручить библиотеке Lombok, аннотировав нужный класс с помощью аннотаций @AllArgsConstructor, @RequiredArgsConstructor и @NoArgsConstructor. Как и следует из названий, эти аннотации приведут к генерированию таких конструкторов:
- @AllArgsConstructor – консктруктор, использующий все поля класса
- @RequiredArgsConstructor – конструктор, использующий все final поля класса
- @NoArgsConstructor – конструктор без параметров
Эти аннотации можно комбинировать между собой и использовать вместе с аннотациями @Getter и @Setter.
Давайте определим класс Person с аннотациями @NoArgsConstructor и @AllArgsConstructor:
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class Person { private String firstName; private String secondName; private Address address; }
public class ConstructorLombok { public static void main(String[] args) { Person a = new Person(); a.setFirstName("Alice"); System.out.println(a.getFirstName()); Person b = new Person("Bob", "Marley", new Address()); System.out.println(b.getFirstName()); } }
Как вы видите, Lombok сгенерировал конструктор без параметров и конструктор со всеми параметрами.
Примечание: при использовании в классе нестатических final полей невозможно использовать аннотацию @NoArgsConstructor, так как в конструкторе без параметров такие поля не будут инициализированы.
@Getter @Setter @NoArgsConstructor // эту аннотацию использовать нельзя @RequiredArgsConstructor @AllArgsConstructor public class Person { private final String firstName; private String secondName; private Address address; }
Методы toString, equals, и hashCode
Для создания метода toString воспользуйтесь аннотацией @ToString:
@Getter @Setter @ToString public class Person { private String firstName; private String secondName; private Address address; }
public class ToStringLombok { public static void main(String[] args) { Person a = new Person(); a.setFirstName("Nicola"); a.setSecondName("Tesla"); System.out.println(a); } }
Выполнение данного кода выведет в консоль следующий текст:
Person(firstName=Nicola, secondName=Tesla, address=null)
Методы equals и hashCode генерируются с помощью аннотации @EqualsAndHashCode. Для простых классов вполне ясно и понятно использовать генерирование этих методов, но в нетривиальных случаях рекомендуется создавать equals и hashCode вручную (или средствами IDE).
Все методы воедино
Зачастую аннотации @Getter, @Setter, @ToString, @EqualsAndHashCode, и @RequiredArgsConstructor используются вместе для одного класса. Для такого типового подхода существует аннотация @Data, объединяющая все перечисленные аннотации.
С помощью аннотации @Data будут сгенерированы геттеры и сеттеры, конструктор со всеми final полями, методы toString, equals и hashCode. Эти два класса равнозначны:
@RequiredArgsConstructor @Getter @Setter @ToString @EqualsAndHashCode public class PersonA { private String firstName; private String secondName; private Address address; }
@Data public class PersonB { private String firstName; private String secondName; private Address address; }
Method chaining
Предположим, у нас есть класс с множеством полей. Использовать конструктор со всеми аргументами – не вариант, получится слишком длинный список аргументов. Вызывать по одному сеттеру в каждой строке может быть тоже непрактично. В этом случае можно воспользоваться аннотацией @Builder на нужном классе и использовать любой набор полей для построения объекта:
public class UserLombokExample { public static void main(String[] args) { User user = User.builder() .person(new Person()) .id(1337L) .username("alex") .build(); System.out.println(user); } }
@Builder @ToString public class User { private final Long id; private String username; private char[] password; private Person person; private List<String> actions; }
Начните построение объекта с вызова метода builder(), затем используйте нужные сеттеры, после чего вызовите метод build() для построения объекта.
Логгеры
Библиотеку Lombok можно использовать не только для моделей и POJO, но и для других классов – например, сервисов. Если в классе используется логгер, то генерирование этого поля можно поручить Lombok.
Например, вместо данного кода:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LogLombok { private static final Logger LOG = LoggerFactory.getLogger(LogLombok.class); public static void main(String[] args) { LOG.info("Just test"); } }
Можно написать следующий код, используя @Slf4j:
import lombok.extern.java.Log; @Slf4j public class LogLombok2 { public static void main(String[] args) { log.info("Just test"); } }
В аннотированном классе будет создано такое final поле с именем log.
Помимо @Slf4j, в Lombok есть ещё аннотации @Log и @CommonsLog. Эти аннотации отвечают за генерацию переменных следующих типов:
- @Log – java.util.logging.Logger
- @Slf4j – org.slf4j.Logger
- @CommonsLog – org.apache.commons.logging.Log
NonNull
Если пометить поле аннотацией @NonNull, то в случае, если будет попытка присвоить данному полю значение null, Lombok выбросит исключение:
import lombok.NonNull; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class StrictUser { @NonNull private final Long id; private String username; }
public class NonNullLombok { public static void main(String[] args) { StrictUser user = new StrictUser(null); // NullPointerException } }
Такое поведение будет аналогично тому, если бы мы написали в начале конструктора или сеттера проверку на null:
public StrictUser(@NonNull Long id) { Objects.requireNonNull(id); this.id = id; }
Переменные @var и константы @val
В Lombok есть интересные аннотации @var для обозначения «изменяемых» переменных и @val для констант. Обе эти аннотации применяются для обозначения локальных переменных.
Начиная с Java 10, синтаксис языка позволяет делать то же самое. Можно использовать val для объявления локальной константы и var для объявления локальной переменной. Особенностью данных двух ключевых слов является то, что тип переменной (или константы) будет определён компилятором автоматически. То есть не потребуется указывать тип переменной (константы) вручную:
import lombok.val; import lombok.var; public class ValVarLombok { public static void main(String[] args) { val pi = 3.1415926; var speed = 100; pi = 4; // ошибка компиляции speed = 240; } }
Данные аннотации можно использовать и в «классическом» стиле:
import lombok.val; import lombok.var; public class ValVarLombok2 { public static void main(String[] args) { @val double pi = 3.1415926; @var double speed = 100; System.out.println("pi=" + pi); System.out.println("speed=" + speed); pi = 4; speed = 240; System.out.println("pi=" + pi); System.out.println("speed=" + speed); } }
В этом случае ошибки компиляции не будет, но значение константы не изменится при попытке её переопределить.
Заключение
В данной статье мы рассказали о ключевых возможностях библиотеки Lombok. С помощью Lombok вы можете упростить и ускорить ращработку программ, используя аннотации длягенерирования конструкторов (@AllArgsConstructor, @RequiredArgsConstructor и @NoArgsConstructor), геттеров и сеттеров (@Getter, @Setter), генерировать стандартные методы (@ToString, @EqualsAndHashCode), генерировать поле для логгера (@Log, @Slf4j, @CommonsLog), использовать функциональность val и var в версиях ниже Java 10. Дерзайте!