Как использовать аннотацию @Builder из проекта Lombok?

Ответ

@Builder — это аннотация Lombok, которая автоматически генерирует код для реализации паттерна Builder. Это удобный и безопасный способ создания объектов, особенно с множеством опциональных полей.

Базовый пример:

import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class User {
    private final Long id; // final поле
    private String name;
    private String email;
    private int age;
}

// Использование:
User user = User.builder()
    .id(1L)
    .name("Alice")
    .email("alice@example.com")
    .age(30)
    .build();

Расширенные возможности:

  1. @Builder на методе: Позволяет создать билдер для конкретного конструктора или фабричного метода.

    public class Car {
        private String model;
        private int year;
    
        @Builder
        public static Car createCar(String model, int year) {
            Car car = new Car();
            car.model = model;
            car.year = year;
            return car;
        }
    }
    // Использование: Car car = Car.createCarBuilder().model("Tesla").year(2023).build();
  2. Кастомизация имен методов:
    @Builder(builderMethodName = "newBuilder", buildMethodName = "create")
  3. Наследование: Для классов с иерархией используйте @SuperBuilder.

    @SuperBuilder
    public class Parent { private String parentField; }
    
    @SuperBuilder
    public class Child extends Parent { private String childField; }
    // Child child = Child.builder().parentField("A").childField("B").build();

Преимущества:

  • Неизменяемость: Позволяет создавать immutable-объекты, если все поля final.
  • Читаемость: Цепочка вызовов делает код создания объекта наглядным.
  • Безопасность: Исключает ошибки, связанные с неправильным порядком аргументов конструктора.

Ограничение: Нельзя использовать @Builder вместе с @Data или @Value без явного определения всех полей в конструкторе.

Ответ 18+ 🔞

А, ну вот, смотри, смотри, смотри! Подъехал очередной вопрос про эту аннотацию, которая у всех на слуху. @Builder, блядь. Ну, в общем, это такая штука от Ломбока, которая, понимаешь, сама за тебя код пишет, чтобы ты мог объекты строить по кирпичикам, как в Лего. Особенно когда полей дохуища и половина из них необязательные. Чтоб не городить конструкторов на 15 параметров, где всё перепутаешь, и не плодить кучу сеттеров.

Самый простой случай, чтоб понятно было: Смотри, вот объявляешь класс, вешаешь на него @Builder и всё, пиздец, готово. Он тебе сам статический метод builder() сгенерирует.

import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class User {
    private final Long id; // final, значит, неизменяемое, только через билдер
    private String name;
    private String email;
    private int age;
}

// А юзать вот так, красиво, по цепочке:
User user = User.builder()
    .id(1L)
    .name("Alice")
    .email("alice@example.com")
    .age(30)
    .build();

Видишь? Никакого геморроя. Собрал, что надо, и build() в конце, как вишенку на торт. Объект готов, поля проинициализированы, всё тип-топ.

А теперь, блядь, тонкости, которые могут вылезти, как геморрой в неподходящий момент:

  1. На методе можно вешать. Допустим, тебе не весь класс надо строить, а только какой-то хитрый фабричный метод. Пожалуйста!

    public class Car {
        private String model;
        private int year;
    
        @Builder // Вешаем на метод, а не на класс!
        public static Car createCar(String model, int year) {
            Car car = new Car();
            car.model = model;
            car.year = year;
            return car;
        }
    }
    // И тогда юзать вот так, ёпта: Car car = Car.createCarBuilder().model("Tesla").year(2023).build();

    Сгенерируется отдельный билдер именно для этого метода. Удобно, если логика создания нестандартная.

  2. Имена методов поменять можно. Не нравится builder() и build()? Ну, иди нахуй, меняй!

    @Builder(builderMethodName = "newBuilder", buildMethodName = "create")

    Теперь будет User.newBuilder().name("Bob").create(). Хочешь — назови собратьПользователя, но это уже на твоей совести.

  3. С наследованием — отдельная песня. Обычный @Builder нахуй сломается, если у тебя класс-родитель и класс-ребёнок. Для этого, блядь, есть @SuperBuilder. Это как @Builder, но с префиксом "супер", потому что задача сложнее.

    @SuperBuilder
    public class Parent { private String parentField; }
    
    @SuperBuilder
    public class Child extends Parent { private String childField; }
    // И вот оно, счастье: Child child = Child.builder().parentField("A").childField("B").build();

    Без @SuperBuilder поля родителя в билдере ребёнка просто не появятся, и будешь сидеть и чесать репу.

Ну и зачем это всё, спросишь? А затем, чувак:

  • Неизменяемость (immutability). Если все поля final, то объект после build() уже не поменяешь. Надёжно, как швейцарские часы, блядь.
  • Читаемость. Сразу видно, какое поле каким значением инициализируется. Не надо гадать, что там за new User(1, null, 30, "alice@...").
  • Безопасность. Не перепутаешь порядок аргументов, потому что их нет, есть только именованные сеттеры.

Но! Есть один важный момент, про который все забывают, а потом охуевают. Нельзя просто так взять и навесить @Builder на класс, который уже помечен @Data или @Value. Точнее, можно, но он сгенерирует билдер только для полей, которые есть в явно определённом конструкторе. Так что либо явно все поля в конструктор пихай, либо используй @Builder на самом конструкторе. А то получишь билдер с половиной полей и будешь искать, где же остальные, ёпта.

Вот такая, блядь, магия. Кажется, мелочь, а экономит кучу времени и нервов. Главное — не переусердствовать и понимать, что под капотом происходит, а то однажды этот сгенерированный код тебе такую подлянку устроит, что мало не покажется.