Collection

Определение

java.util.Collection<E> — корневой интерфейс для контейнеров, которые представляют группу элементов. От него наследуются List, Set и Queue. Интерфейс Map стоит отдельно: карта хранит пары «ключ — значение», а не просто элементы.

public interface Collection<E> extends Iterable<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object value);
    boolean add(E value);
    boolean remove(Object value);
    Iterator<E> iterator();
    // bulk-операции, массивы, Stream API и другие методы
}

Программировать через Collection полезно, когда вызывающему коду не нужны порядок, индекс или уникальность:

int countLongNames(Collection<String> names) {
    int count = 0;
    for (String name : names) {
        if (name.length() >= 8) {
            count++;
        }
    }
    return count;
}

Метод примет и список, и множество. Если контракт требует сохранить порядок или дубликаты, тип Collection уже слишком общий — нужен List.

Основные группы операций

ГруппаМетодыСмысл
Состояниеsize, isEmpty, containsузнать размер и проверить наличие
Изменениеadd, remove, clearизменить содержимое
Массовые операцииaddAll, removeAll, retainAll, containsAllработать с другой коллекцией
Обходiterator, forEach, spliteratorпоследовательно обработать элементы
ПредставлениеtoArrayполучить массив
Потокstream, parallelStreamпостроить конвейер Stream API

Часть операций является необязательной. Немодифицируемая коллекция может реализовать add и remove выбрасыванием UnsupportedOperationException. Поэтому тип Collection<E> сам по себе не обещает возможность изменения.

Collection и Collections

  • Collection — интерфейс экземпляра коллекции.
  • Collections — утилитный класс со статическими алгоритмами и фабриками: сортировка, поиск, перестановка, немодифицируемые представления и другие операции.
List<Integer> numbers = new ArrayList<>(List.of(3, 1, 2));
Collections.sort(numbers);
Collection<Integer> readOnlyView = Collections.unmodifiableCollection(numbers);

unmodifiableCollection создаёт представление, а не копию. Изменения исходной коллекции будут видны через него. Для независимого неизменяемого снимка обычно создают копию, например List.copyOf(source).

Инварианты и ловушки

  • contains и remove(Object) обычно опираются на equals; для хеш-реализаций важен также hashCode.
  • Во время обхода нельзя произвольно менять обычную коллекцию через неё саму: используйте Iterator.remove, специальную concurrent-реализацию или сначала соберите изменения.
  • size() у большинства коллекций — O(1), но интерфейс не задаёт алгоритмическую сложность.
  • Допустимость null, порядок обхода и потокобезопасность определяет конкретная реализация.
  • remove(1) у List<Integer> удаляет элемент по индексу; для удаления значения нужен remove(Integer.valueOf(1)).

Вопросы на собеседовании

  1. Почему Map не наследует Collection?
  2. Чем Collection отличается от Collections?
  3. Что означает «необязательная операция» в контракте коллекции?
  4. Чем немодифицируемое представление отличается от неизменяемой копии?
  5. Когда параметр метода стоит объявлять как Collection, а когда как List?

Связанные заметки

Иерархия коллекций · List · Set · Queue and Deque · Map · Iterable · Equals и hashCode