Ответ
@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();
Расширенные возможности:
-
@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(); - Кастомизация имен методов:
@Builder(builderMethodName = "newBuilder", buildMethodName = "create") -
Наследование: Для классов с иерархией используйте
@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() в конце, как вишенку на торт. Объект готов, поля проинициализированы, всё тип-топ.
А теперь, блядь, тонкости, которые могут вылезти, как геморрой в неподходящий момент:
-
На методе можно вешать. Допустим, тебе не весь класс надо строить, а только какой-то хитрый фабричный метод. Пожалуйста!
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();Сгенерируется отдельный билдер именно для этого метода. Удобно, если логика создания нестандартная.
-
Имена методов поменять можно. Не нравится
builder()иbuild()? Ну, иди нахуй, меняй!@Builder(builderMethodName = "newBuilder", buildMethodName = "create")Теперь будет
User.newBuilder().name("Bob").create(). Хочешь — назовисобратьПользователя, но это уже на твоей совести. -
С наследованием — отдельная песня. Обычный
@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 на самом конструкторе. А то получишь билдер с половиной полей и будешь искать, где же остальные, ёпта.
Вот такая, блядь, магия. Кажется, мелочь, а экономит кучу времени и нервов. Главное — не переусердствовать и понимать, что под капотом происходит, а то однажды этот сгенерированный код тебе такую подлянку устроит, что мало не покажется.