Lombok – це заснована на анотаціях бібліотека Java, що дозволяє скоротити написання шаблонного коду. Lombok пропонує різноманітні анотації, мета котрих замінити зайвий повторюваний код.

Наприклад, Lombok позбавляє від написання конструкторів, методів toString(), equals() і hashCode(), замість цього потрібно просто додати кілька анотацій. Також ця бібліотека інтегрується з IDE, завдяки чому робота сприймається так, наче ви написали весь шаблонний код самі.

Додавання Lombok в проект

Для підключення Lombok до проекту побудованому на maven, потрібно додати залежність до pom файлу:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
    <scope>provided</scope>
</dependency>

Крім того, додати залежність Lombok до конфігураційного розділу maven-compiler-plugin наступним чином:

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>3.12.1</version>
			<configuration>
				<source>${maven.compiler.source}</source>
				<target>${maven.compiler.target}</target>
				<annotationProcessorPaths>
					<path>
						<groupId>org.projectlombok</groupId>
						<artifactId>lombok</artifactId>
						<version>1.18.30</version>
					</path>
				</annotationProcessorPaths>
			</configuration>
		</plugin>
	</plugins>
</build>

Налаштування Lombok в IntelliJ IDEA

Для інтеграції бібліотеки Lombok в середу розробки IntelliJ IDEA, потрібно встановити та активувати плагін Lombok:

Ще один крок, перейти в розділ налаштувань за шляхом:

Settings | Build, Execution, Deployment | Compiler | Annotation Processors

Та активувати наступні налаштування:

Тепер можна переходити до прикладів використання анотацій Lombok.

Анотації @Getter та @Setter

Можна анотувати будь-яке поле за допомогою @Getter та/або @Setter, щоб дозволити lombok автоматично генерувати геттер/сеттер за замовчуванням для цього поля.

  • @Getter – для поля, що має назву (наприклад value) буде згенеровано метод getValue() (або isValue(), якщо поле має тип boolean), та за замовчуванням просто повертає значення поля
  • @Setter – для поля, що має назву (наприклад value) буде згенеровано метод setValue(), котрий приймає один параметр того самого типу, що й поле, та встановлює це значення для поля

Також анотаціями @Getter та/або @Setter можна позначити весь клас. В такому випадку, ці анотації буде застосовано до всіх нестатичних полів в цьому класі.

Згенеровані методи getter/setter будуть мати модифікатор доступу public. Є можливість явно вказати рівень доступу за допомогою AccessLevel, як показано в прикладі нижче. Наявні рівні доступу: PUBLIC, PROTECTED, PACKAGE та PRIVATE.

Оголошення класу з використанням анотацій @Getter та @Setter на рівні класу:

@Getter
@Setter
public class Person {

    private String fullName;
    private int age;
    @Setter(AccessLevel.PROTECTED)
    private boolean active;
}

Слід звернути увагу, що до поля active для прикладу застосовано анотацію @Setter з AccessLevel.PROTECTED (згенерований метод setActive буде мати модифікатор доступу protected).

Приклад використання класу Person:

public class Main {

    public static void main(String[] args) {
        var person = new Person();
        person.setFullName("Тарас Очерет");
        person.setActive(true);

        System.out.println(person.getFullName());
        System.out.println(person.isActive());
    }
}

Клас Person оголошений звичайним способом без використання Lombok:

public class Person {

    private String fullName;
    private int age;
    private boolean active;

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public boolean isActive() {
        return active;
    }

    protected void setActive(boolean active) {
        this.active = active;
    }
}

Анотації @NoArgsConstructor та @AllArgsConstructor

Ці анотації застосовуються на рівні класу, та відповідають за генерацію конструкторів:

  • @NoArgsConstructor – створить конструктор без параметрів
  • @AllArgsConstructor – створить конструктор, що містить по одному параметру для кожного поля в класі

Оголошення класу з використанням Lombok анотацій @NoArgsConstructor та @AllArgsConstructor:

@NoArgsConstructor
@AllArgsConstructor
public class Person {

    private String fullName;
    private int age;
    private boolean active;
}

Оголошення класу класичним способом без використання Lombok:

public class Person {

    private String fullName;
    private int age;
    private boolean active;

    public Person() {}

    public Person(String fullName, int age, boolean active) {
        this.fullName = fullName;
        this.age = age;
        this.active = active;
    }
}

Анотація @RequiredArgsConstructor

@RequiredArgsConstructor – генерує конструктор з одним параметром для кожного поля, яке вимагає спеціальної обробки, а саме:

  • усі неініційовані final поля
  • будь-які поля, позначені як @NonNull та неініційовані в місці оголошення

Для полів, позначених @NonNull, також генерується явна перевірка на null. Конструктор створить виняток NullPointerException, якщо будь-який з параметрів, призначених для полів позначених @NonNull, містить значення null. Порядок параметрів відповідає порядку оголошення полів у класі.

Оголошення класу з використанням Lombok анотацій @RequiredArgsConstructor та @NonNull:

@RequiredArgsConstructor
public class Person {

    @NonNull private String fullName;
    private final int age;
    private boolean active;
}

Оголошення класу класичним способом без використання Lombok:

public class Person {

    private String fullName;
    private final int age;
    private boolean active;

    public Person(String fullName, int age) {
        if(fullName == null) {
            throw new NullPointerException("fullName can not be null");
        }
        this.fullName = fullName;
        this.age = age;
    }
}

Також слід додати, що анотації @NoArgsConstructor, @AllArgsConstructor та @RequiredArgsConstructor під час генерації конструкторів ігнорують статичні поля.

Кожна з цих анотацій для генерації конструкторів, допускає альтернативну форму, де згенерований конструктор є приватним, і генерується додатковий статичний фабричний метод, який обгортає приватний конструктор. Цей режим активується шляхом надання значення атрибуту staticName анотації, наприклад: @AllArgsConstructor(staticName=”of”):

@AllArgsConstructor(staticName = "of")
@ToString
public class Person {

    private String fullName;
    private int age;
    private boolean active;
}

Протестую клас Person:

public class Main {

    public static void main(String[] args) {
        Person person = Person.of("Тарас Чубай", 30, true);
        System.out.println(person.toString());
    }
}

Тепер аналог класу зі статичним фабричним методом без використання Lombok:

public class Person {

    private String fullName;
    private int age;
    private boolean active;

    private Person(String fullName, int age, boolean active) {
        this.fullName = fullName;
        this.age = age;
        this.active = active;
    }

    public static Person of(String fullName, int age, boolean active) {
        return new Person(fullName, age, active);
    }

    @Override
    public String toString() {
        return "Person{" +
                "fullName='" + fullName + '\'' +
                ", age=" + age +
                ", active=" + active +
                '}';
    }
}

Анотація @ToString

Якщо клас анотовано @ToString, Lombok згенерує для нього метод toString() (докладніше Java – метод toString()). За замовчуванням буде повертатися рядок, що містить ім’я класу, за яким слідує перелік не статичних полів класу, у форматі ім’я=значення, розділених комами:

@AllArgsConstructor
@ToString
public class Person {

    private String fullName;
    private int age;
    private boolean active;
}


public class Main {

    public static void main(String[] args) {
        var person = new Person("Валентин Опенько", 30, false);
        System.out.println(person);
    }
}


// Результат: Person(fullName=Валентин Опенько, age=30, active=false)

Додавши до анотації @ToString параметр includeFieldNames=false, з результуючого рядка будуть виключені імена полів:

@AllArgsConstructor
@ToString(includeFieldNames = false)
public class Person {

    private String fullName;
    private int age;
    private boolean active;
}


public class Main {

    public static void main(String[] args) {
        var person = new Person("Валентин Опенько", 30, false);
        System.out.println(person);
    }
}


// Результат: Person(Валентин Опенько, 30, false)

За замовчуванням при генерації методу toString() враховуються всі нестатичні поля класу. Якщо потрібно, щоб Lombok проігнорував окреме поле, можна анотувати його @ToString.Exclude:

@AllArgsConstructor
@ToString
public class Person {

    private String fullName;
    private int age;
    @ToString.Exclude private boolean active;
}

// Результат: Person(fullName=Валентин Опенько, age=30)

Як варіант, можна самостійно вказати поля, котрі повинні повертатися методом toString(). Для цього потрібно анотувати клас @ToString(onlyExplicitlyIncluded=true), після чого позначити @ToString.Include кожне поле, яке слід включити в рядок:

@AllArgsConstructor
@ToString(onlyExplicitlyIncluded = true)
public class Person {

    @ToString.Include private String fullName;
    @ToString.Include private int age;
    private boolean active;
}

// Результат: Person(fullName=Валентин Опенько, age=30)

Анотація @EqualsAndHashCode

Для класу анотованого @EqualsAndHashCode, Lombok автоматично реалізує методи equals() та hashCode(). За замовчуванням враховуватимуться всі нестатичні поля класу.

Можна вплинути на те, які поля не будуть використовуватися, анотувавши їх @EqualsAndHashCode.Exclude:

@AllArgsConstructor
@EqualsAndHashCode
public class Person {

    @EqualsAndHashCode.Exclude private int id;
    private String fullName;
    private int age;
    private boolean active;
}

Як варіант, можна анотувати клас за допомогою @EqualsAndHashCode(onlyExplicitlyIncluded = true), а потім точно вказати, які поля слід використовувати, позначивши їх @EqualsAndHashCode.Include:

@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Person {

    private int id;
    @EqualsAndHashCode.Include private String fullName;
    @EqualsAndHashCode.Include private int age;
    private boolean active;
}

Оголошення класу з методами equals() та hashCode() класичним способом, без використання Lombok:

public class Person {

    private int id;
    private String fullName;
    private int age;
    private boolean active;

    public Person(int id, String fullName, int age, boolean active) {
        this.id = id;
        this.fullName = fullName;
        this.age = age;
        this.active = active;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person person)) return false;

        if (age != person.age) return false;
        if (active != person.active) return false;
        return fullName.equals(person.fullName);
    }

    @Override
    public int hashCode() {
        int result = fullName.hashCode();
        result = 31 * result + age;
        result = 31 * result + (active ? 1 : 0);
        return result;
    }
}

Анотація @Data

@Data – це скорочена анотація, що поєднує в собі можливості @Getter, @Setter, @RequiredArgsConstructor, @ToString та @EqualsAndHashCode. Таким чином, @Data генерує весь шаблонний код, залучений до роботи з об’єктами POJO (Plain Old Java Objects):

@Data
public class Person {

    private String fullName;
    private int age;
    private boolean active;
}

Анотація @Value

@Value – це незмінний варіант @Data. З цією анотацією, Lombok за замовчуванням робить всі поля private та final. Крім того, сеттери не генеруються, а клас позначається як final. Таким чином, від цього класу не можна успадковуватись. Так само як і у випадку з @Data, створюються реалізації toString(), equals() і hashCode():

@Value
public class Person {

    String fullName;
    int age;
    boolean active;
}

Анотація @Builder

Використовується при потребі створити об’єкт builder, який дозволяє створювати об’єкти, дотримуючись покрокової процедури, наприклад:  

Person person = Person.builder().fullName("Валентин Дуць").age("Maria").active(true).build();

Це особливо корисно, під час роботи з великими класами, що містять кілька полів і більше. Замість використання конструктора з багатьма полями, можна спробувати цей підхід. При використанні анотації @Builder, Lombok генерує клас, що реалізує шаблон програмування builder:

@Builder
@ToString
public class Person {

    private String fullName;
    private int age;
    private boolean active;
}


public class Main {

    public static void main(String[] args) {
        Person person = Person.builder()
                .fullName("Роман Гринь")
                .age(27)
                .active(false)
                .build();

        System.out.println(person);
    }
}

// Результат: Person(fullName=Роман Гринь, age=27, active=false)

Документація проекту Lombok доступна за посиланням:

Project Lombok


Мітки: