Что нужно для того, чтобы поле в классе было обязательным для конструктора в Java
Что проверяют
Понимаете ли вы, что обязательность поля обеспечивается не пометкой в документации, а отсутствием способа создать объект без него. Это разговор про инварианты класса и про то, кто отвечает за валидность объекта.
Как отвечать
Обязательность даёт связка из трёх вещей:
- поле
final: компилятор потребует присвоить его в каждом конструкторе, забыть случайно не выйдет; - конструктор со всеми обязательными параметрами и отсутствие конструктора без аргументов: если пустого конструктора нет, объект без поля просто не собрать;
- проверка в конструкторе:
Objects.requireNonNull(name)или явное исключение на пустой строке, чтобыnullне проехал дальше по коду.
public final class Client {
private final String name;
public Client(String name) {
this.name = Objects.requireNonNull(name, "name");
}
}Если обязательных полей много и рядом есть необязательные, берут Builder, но обязательные параметры отдают в его конструктор или в фабричный метод, а не в отдельные сеттеры. Иначе билдер снова разрешает собрать объект без поля, и ошибка уезжает в рантайм.
Короткий способ закрыть тему: record. Канонический конструктор принимает все компоненты, поля неизменяемы, а проверки пишут в компактном конструкторе.
Где спотыкаются
Считают, что модификатор private делает поле обязательным. Он ограничивает доступ, а не требует значение: объект с null внутри создаётся так же, просто снаружи поле не видно.
Полагаются на аннотации вроде @NotNull. Аннотация сработает, только если объект проходит через валидатор или проверку среды разработки, а прямой вызов конструктора она не остановит: это подсказка, а не гарантия языка.
Добавляют пустой конструктор ради фреймворка и ломают инвариант. Библиотеки сериализации и слои доступа к данным умеют создавать объект через конструктор с параметрами, и настроить это дешевле, чем открыть всем способ получить полупустой объект.