Как сделать класс immutable

51. Сделать класс immutable

Условие задачи:
Дан класс A с полями Integer a и List<Object> b. Необходимо сделать его неизменяемым.

Код:

class A {
    Integer a;
    List<Object> b;
}

Спойлеры к решению

Подсказки
💡 Запрети наследование от класса.
💡 Сделай все поля private final.
💡 Устанавливай значения только через конструктор.
💡 Не добавляй сеттеры.
💡 Создавай защитную копию изменяемой коллекции.
💡 Учитывай, что копирование списка не делает неизменяемыми его элементы.

Решение
public final class A {

    private final Integer a;
    private final List<Object> b;

    public A(Integer a, List<Object> b) {
        this.a = a;
        this.b = b == null
                ? List.of()
                : List.copyOf(b);
    }

    public Integer getA() {
        return a;
    }

    public List<Object> getB() {
        return b;
    }
}

Класс нельзя унаследовать, его поля нельзя переназначить после создания, а список копируется и хранится в неизменяемом виде.

Изменение исходного списка не повлияет на состояние объекта:

List<Object> source = new ArrayList<>();
source.add("value");

A object = new A(10, source);

source.add("another");

System.out.println(object.getB()); // [value]

Попытка изменить список через геттер завершится исключением:

object.getB().add("new value");

List.copyOf() выполняет поверхностное копирование. Поэтому для полной неизменяемости элементы списка тоже должны быть immutable. Если внутри находятся изменяемые объекты, для них необходимо создавать глубокие защитные копии.