← Назад к вопросам

Что такое иммутабельность?

1.7 Middle🔥 171 комментариев
#ООП

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое иммутабельность

Иммутабельность (immutability) — это свойство объекта, при котором его состояние не может быть изменено после создания. Иммутабельный объект гарантирует, что все его поля остаются неизменными на протяжении всего жизненного цикла.

Зачем нужна иммутабельность

  1. Thread-safety — иммутабельные объекты безопасны в многопоточной среде, так как не требуют синхронизации
  2. Безопасность в совместном доступе — разные потоки могут безопасно делиться одним объектом
  3. Кеширование — можно безопасно кешировать значения
  4. Предсказуемость — состояние объекта не меняется неожиданно
  5. Функциональное программирование — основа для FP парадигмы

Правила создания иммутабельного класса

// Шаг 1: объявить класс final
public final class ImmutablePerson {
    // Шаг 2: все поля private и final
    private final String name;
    private final int age;
    private final List<String> hobbies;
    
    // Шаг 3: инициализировать в конструкторе
    public ImmutablePerson(String name, int age, List<String> hobbies) {
        this.name = name;
        this.age = age;
        // Шаг 4: защитить от внешних изменений (defensive copy)
        this.hobbies = new ArrayList<>(hobbies);
    }
    
    // Шаг 5: no setters, только getters
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    // Шаг 6: возвращать копии mutable объектов
    public List<String> getHobbies() {
        return new ArrayList<>(hobbies);
    }
    
    // Шаг 7: переопределить equals, hashCode, toString
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof ImmutablePerson)) return false;
        ImmutablePerson other = (ImmutablePerson) obj;
        return Objects.equals(name, other.name) && 
               age == other.age &&
               Objects.equals(hobbies, other.hobbies);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age, hobbies);
    }
}

Пример использования

public class ImmutabilityExample {
    public static void main(String[] args) {
        List<String> hobbies = new ArrayList<>(Arrays.asList("reading", "coding"));
        ImmutablePerson person = new ImmutablePerson("Alice", 30, hobbies);
        
        // Попытка изменить список извне не повлияет на объект
        hobbies.add("gaming");
        System.out.println(person.getHobbies()); // [reading, coding]
        
        // Попытка изменить возвращённый список
        List<String> returned = person.getHobbies();
        returned.add("gaming");
        System.out.println(person.getHobbies()); // [reading, coding]
    }
}

Встроенные иммутабельные классы Java

// String — иммутабельна
String str = "hello";
// str.toUpperCase() возвращает новую строку, не меняя оригинал

// Integer, Long, Double — иммутабельны
Integer num = Integer.valueOf(5);

// LocalDateTime, LocalDate — иммутабельны
LocalDateTime now = LocalDateTime.now();
LocalDateTime later = now.plusDays(1); // новый объект

// Collections.unmodifiableXXX()
List<String> unmodifiable = Collections.unmodifiableList(
    new ArrayList<>(Arrays.asList("a", "b"))
);
// unmodifiable.add("c"); // UnsupportedOperationException

Иммутабельность в Java records (Java 14+)

// Record автоматически создаёт иммутабельный класс
public record Person(
    String name,
    int age,
    List<String> hobbies
) {
    // Компилятор генерирует:
    // - final поля
    // - конструктор
    // - getters (name(), age(), hobbies())
    // - equals, hashCode, toString
    
    // Но нужно защитить mutable поле от внешних изменений
    public Person {
        hobbies = new ArrayList<>(hobbies);
    }
}

Преимущества иммутабельности

// 1. Thread-safety без синхронизации
ImmutablePerson person1 = new ImmutablePerson("Bob", 25, List.of());
ImmutablePerson person2 = person1; // безопасно делиться между потоками

// 2. Безопасное использование в HashMap/HashSet
Set<ImmutablePerson> set = new HashSet<>();
set.add(person1);
// hashCode никогда не поменяется

// 3. Предсказуемый код
ImmutablePerson original = new ImmutablePerson("Charlie", 35, List.of());
ImmutablePerson copy = new ImmutablePerson(
    original.getName(), 
    original.getAge(), 
    original.getHobbies()
);
// original и copy гарантированно равны и не изменятся

Недостатки иммутабельности

// 1. Больше объектов в памяти (new для каждого изменения)
ImmutablePerson person = new ImmutablePerson("David", 40, List.of());
// для изменения возраста нужен новый объект
ImmutablePerson updated = new ImmutablePerson("David", 41, List.of());

// 2. Сложнее работать с большими объектами
// Часто используют Builder pattern
public class PersonBuilder {
    private String name;
    private int age;
    private List<String> hobbies = new ArrayList<>();
    
    public PersonBuilder withName(String name) {
        this.name = name;
        return this;
    }
    
    public ImmutablePerson build() {
        return new ImmutablePerson(name, age, hobbies);
    }
}

Вывод

Иммутабельность — один из ключевых принципов функционального программирования. Используй её для:

  • Значимых объектов (Entity, Value Objects)
  • Многопоточного кода
  • Кешируемых данных
  • Ключей в HashMap/HashSet
Что такое иммутабельность? | PrepBro