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

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

2.0 Middle🔥 221 комментариев
#Коллекции

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

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

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

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

Иммутабельная коллекция (Immutable Collection) — это коллекция, которая не может быть изменена после создания. После инициализации нельзя добавлять, удалять или модифицировать элементы. Это мощный инструмент для безопасности потоков и предотвращения ошибок.

Проблемы с изменяемыми коллекциями

// ❌ ПРОБЛЕМА: изменяемая коллекция
final List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");

// Кто-то может изменить список в другом потоке
list.clear(); // Ops! Список очищен
list.remove(0);
list.set(0, "orange");

// В многопоточной среде это приводит к race conditions
public void processItems(List<String> items) {
    for (String item : items) {
        // Во время итерации кто-то может изменить items
        // ConcurrentModificationException!
        process(item);
    }
}

Создание иммутабельных коллекций

1. Collections.unmodifiable*

import java.util.*;

public class UnmodifiableExample {
    
    public static void main(String[] args) {
        List<String> mutableList = new ArrayList<>();
        mutableList.add("apple");
        mutableList.add("banana");
        
        // ✅ Создаём неизменяемую коллекцию
        List<String> immutableList = Collections.unmodifiableList(mutableList);
        
        // ❌ UnsupportedOperationException
        immutableList.add("orange"); // Ошибка!
        immutableList.remove(0); // Ошибка!
        immutableList.set(0, "grape"); // Ошибка!
        
        // ⚠️ Но! Если изменить исходный список, изменится и "иммутабельный"
        mutableList.add("pear");
        System.out.println(immutableList); // [apple, banana, pear] !
    }
}

// ✅ Иммутабельные коллекции для других типов
Set<Integer> immutableSet = Collections.unmodifiableSet(new HashSet<>(nums));
Map<String, Integer> immutableMap = Collections.unmodifiableMap(new HashMap<>(data));

2. List.of(), Set.of(), Map.of() (Java 9+)

import java.util.*;

public class ModernImmutable {
    
    public static void main(String[] args) {
        // ✅ Java 9+: истинно иммутабельные коллекции
        List<String> list = List.of("apple", "banana", "cherry");
        Set<Integer> set = Set.of(1, 2, 3, 4, 5);
        Map<String, Integer> map = Map.of(
            "apple", 10,
            "banana", 20,
            "cherry", 30
        );
        
        // ❌ UnsupportedOperationException
        list.add("orange"); // Ошибка!
        set.remove(1); // Ошибка!
        map.put("grape", 40); // Ошибка!
        
        // ✅ Полностью безопасно — нет связи с исходными данными
        List<String> fruits = new ArrayList<>();
        fruits.add("apple");
        List<String> immutable = List.copyOf(fruits);
        fruits.add("banana"); // Не влияет на immutable
    }
}

Иммутабельные коллекции в многопоточной среде

import java.util.concurrent.*;
import java.util.*;

public class ThreadSafetyExample {
    
    // ❌ НЕБЕЗОПАСНО
    static class UnsafeUserRepository {
        private List<User> users = new ArrayList<>(); // Изменяемо!
        
        public List<User> getUsers() {
            return users; // Опасно! Кто-то может изменить
        }
    }
    
    // ✅ БЕЗОПАСНО
    static class SafeUserRepository {
        private final List<User> users = List.of(); // Иммутабельно
        
        public List<User> getUsers() {
            return users; // Безопасно! Никто не может изменить
        }
        
        // Если нужна обновка — создаём новый список
        public void addUser(User user) {
            List<User> newUsers = new ArrayList<>(users);
            newUsers.add(user);
            // synchronized и обновляем ссылку
            synchronized (this) {
                this.users = List.copyOf(newUsers);
            }
        }
    }
}

Пример с Streams

import java.util.*;
import java.util.stream.Collectors;

public class StreamImmutable {
    
    public void processData(List<String> data) {
        // ✅ Создаём иммутабельный список из stream
        List<String> uppercase = data.stream()
            .map(String::toUpperCase)
            .collect(Collectors.toUnmodifiableList());
        
        // ✅ Иммутабельный set
        Set<String> uniqueItems = data.stream()
            .collect(Collectors.toUnmodifiableSet());
        
        // ✅ Иммутабельная map
        Map<String, Integer> lengths = data.stream()
            .collect(Collectors.toUnmodifiableMap(
                Function.identity(),
                String::length
            ));
    }
}

Вспомогательные библиотеки

Google Guava ImmutableCollections

import com.google.common.collect.*;

public class GuavaImmutable {
    
    public void examples() {
        // ImmutableList
        ImmutableList<String> list = ImmutableList.of("a", "b", "c");
        ImmutableList<String> list2 = ImmutableList.<String>builder()
            .add("x", "y", "z")
            .add("more items")
            .build();
        
        // ImmutableSet
        ImmutableSet<Integer> set = ImmutableSet.of(1, 2, 3);
        
        // ImmutableMap
        ImmutableMap<String, Integer> map = ImmutableMap.of(
            "a", 1,
            "b", 2
        );
        
        // Все они невозможно изменить
        // list.add("d"); // UnsupportedOperationException
    }
}

Apache Commons Lang

import org.apache.commons.lang3.tuple.Pair;
import java.util.Collections;

public class CommonsImmutable {
    // ...existing code...
}

Иммутабельные классы

import java.util.*;

// ✅ Иммутабельный класс
public final class ImmutableUser {
    private final String name;
    private final int age;
    private final List<String> tags; // Иммутабельная коллекция
    
    public ImmutableUser(String name, int age, List<String> tags) {
        this.name = name;
        this.age = age;
        // Создаём copy для защиты
        this.tags = List.copyOf(tags);
    }
    
    public String getName() { return name; }
    public int getAge() { return age; }
    public List<String> getTags() { return tags; } // Безопасно вернуть
    
    // Для изменения — создаём новый объект
    public ImmutableUser withName(String newName) {
        return new ImmutableUser(newName, this.age, this.tags);
    }
}

Запись параметров (Java 16+)

// ✅ Record — автоматически иммутабельный
public record User(String name, int age, List<String> tags) {
    // Компилятор автоматически создаст:
    // - private final поля
    // - конструктор
    // - getters
    // - equals/hashCode/toString
}

public void example() {
    User user = new User("John", 30, List.of("developer", "java"));
    // user.name = "Jane"; // Ошибка компиляции!
}

Преимущества иммутабельных коллекций

  1. Потокобезопасность — не нужны блокировки
  2. Простота — меньше ошибок логики
  3. Кэширование — можно кэшировать без опасений
  4. Производительность — JVM может оптимизировать
  5. Предсказуемость — значения не изменяются неожиданно

Недостатки

  1. Производительность — copy-on-write медленнее для частых изменений
  2. Памяти — может требовать больше памяти
  3. Гибкость — нельзя просто изменить, нужно создавать новый объект

Лучшие практики

// ✅ Возвращай иммутабельные коллекции из методов
public List<User> getUsers() {
    return Collections.unmodifiableList(users);
    // или
    return List.copyOf(users);
}

// ✅ Создавай иммутабельные коллекции для constans
private static final List<String> VALID_STATUSES = List.of("ACTIVE", "INACTIVE", "DELETED");

// ✅ Используй иммутабельные классы для value objects
public final class Money {
    private final BigDecimal amount;
    private final Currency currency;
    // ...
}

Иммутабельные коллекции — критически важны в современной Java разработке, особенно в многопоточных приложениях!

Что такое иммутабельная коллекция? | PrepBro