Статьи

Полный курс по языку Java — от установки JDK до многопоточности и HTTP-запросов

Коллекции: List, Set, Map

Страница 20 из 30 · 2026-10-25 · 5 мин чтения

Зачем коллекции

Массивы имеют фиксированный размер. Коллекции из java.util растут динамически и дают готовые алгоритмы. Они хранят только объекты, для примитивов используются обертки.

Iterable└── Collection    ├── List    (упорядоченный, с повторами)    ├── Set     (без повторов)    └── Queue   (очередь)Map             (пары ключ-значение, не наследует Collection)

List

import java.util.ArrayList;import java.util.List;public class ListDemo {    public static void main(String[] args) {        List<String> names = new ArrayList<>();        names.add("Анна");        names.add("Борис");        names.add("Вера");        names.add(1, "Глеб");        System.out.println(names);        System.out.println(names.size());        System.out.println(names.get(0));        System.out.println(names.contains("Вера"));        System.out.println(names.indexOf("Борис"));        names.set(0, "Алиса");        names.remove("Вера");        names.remove(0);        System.out.println(names);        for (String name : names) {            System.out.println(name);        }        System.out.println(names.isEmpty());        names.clear();    }}

Фабричный метод List.of создает неизменяемый список:

List<Integer> fixed = List.of(1, 2, 3);fixed.add(4);

Вторая строка бросит UnsupportedOperationException. Изменяемая копия: new ArrayList<>(List.of(1, 2, 3)).

Удаление по значению и по индексу

import java.util.ArrayList;import java.util.List;public class RemoveDemo {    public static void main(String[] args) {        List<Integer> numbers = new ArrayList<>(List.of(10, 20, 30, 40));        numbers.remove(1);        System.out.println(numbers);        numbers.remove(Integer.valueOf(40));        System.out.println(numbers);    }}

remove(int) удаляет по индексу, а для удаления по значению нужен Integer.valueOf.

Безопасное удаление при переборе

import java.util.ArrayList;import java.util.List;public class SafeRemove {    public static void main(String[] args) {        List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));        numbers.removeIf(n -> n % 2 == 0);        System.out.println(numbers);    }}

Удаление внутри for-each вызовет ConcurrentModificationException.

ArrayList и LinkedList

ArrayListLinkedList
Доступ по индексубыстрыймедленный
Вставка в конецбыстробыстро
Вставка в серединумедленнобыстро после поиска места
Памятькомпактномного накладных расходов

В большинстве случаев используйте ArrayList.

Set

Множество не допускает дубликатов.

import java.util.HashSet;import java.util.List;import java.util.LinkedHashSet;import java.util.Set;import java.util.TreeSet;public class SetDemo {    public static void main(String[] args) {        Set<String> hash = new HashSet<>();        hash.add("яблоко");        hash.add("груша");        hash.add("яблоко");        System.out.println(hash.size());        Set<Integer> linked = new LinkedHashSet<>(List.of(3, 1, 2));        System.out.println(linked);        Set<Integer> sorted = new TreeSet<>(List.of(3, 1, 2));        System.out.println(sorted);        Set<Integer> a = new HashSet<>(Set.of(1, 2, 3, 4));        Set<Integer> b = Set.of(3, 4, 5);        Set<Integer> union = new HashSet<>(a);        union.addAll(b);        Set<Integer> intersection = new HashSet<>(a);        intersection.retainAll(b);        Set<Integer> difference = new HashSet<>(a);        difference.removeAll(b);        System.out.println(union);        System.out.println(intersection);        System.out.println(difference);    }}
РеализацияПорядокСкорость
HashSetне гарантированO(1)
LinkedHashSetпорядок добавленияO(1)
TreeSetотсортированO(log n)

Элементы HashSet должны правильно реализовывать equals и hashCode.

Map

import java.util.HashMap;import java.util.Map;public class MapDemo {    public static void main(String[] args) {        Map<String, Integer> ages = new HashMap<>();        ages.put("Анна", 25);        ages.put("Борис", 30);        ages.put("Вера", 28);        System.out.println(ages.get("Анна"));        System.out.println(ages.get("Никто"));        System.out.println(ages.getOrDefault("Никто", 0));        System.out.println(ages.containsKey("Борис"));        System.out.println(ages.containsValue(28));        ages.put("Анна", 26);        ages.remove("Вера");        System.out.println(ages.size());        for (Map.Entry<String, Integer> entry : ages.entrySet()) {            System.out.println(entry.getKey() + " -> " + entry.getValue());        }        for (String key : ages.keySet()) {            System.out.println(key);        }        for (int value : ages.values()) {            System.out.println(value);        }        ages.forEach((k, v) -> System.out.println(k + "=" + v));    }}

Ключи уникальны. Повторный put заменяет значение.

Полезные методы Map

import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class MapMethods {    public static void main(String[] args) {        Map<String, Integer> counts = new HashMap<>();        String text = "to be or not to be";        for (String word : text.split(" ")) {            counts.merge(word, 1, Integer::sum);        }        System.out.println(counts);        Map<String, List<String>> groups = new HashMap<>();        groups.computeIfAbsent("фрукты", k -> new ArrayList<>()).add("яблоко");        groups.computeIfAbsent("фрукты", k -> new ArrayList<>()).add("груша");        System.out.println(groups);        counts.putIfAbsent("new", 0);        counts.compute("to", (k, v) -> v == null ? 1 : v + 10);        System.out.println(counts);    }}

Реализации Map

РеализацияПорядок ключей
HashMapне гарантирован
LinkedHashMapпорядок добавления
TreeMapотсортированный по ключу

Map.of(...) создает неизменяемую карту.

Queue и Deque

import java.util.ArrayDeque;import java.util.Deque;import java.util.LinkedList;import java.util.PriorityQueue;import java.util.Queue;public class QueueDemo {    public static void main(String[] args) {        Queue<String> queue = new LinkedList<>();        queue.offer("первый");        queue.offer("второй");        System.out.println(queue.peek());        System.out.println(queue.poll());        System.out.println(queue.size());        Deque<Integer> stack = new ArrayDeque<>();        stack.push(1);        stack.push(2);        stack.push(3);        System.out.println(stack.pop());        System.out.println(stack.peek());        PriorityQueue<Integer> priority = new PriorityQueue<>();        priority.add(5);        priority.add(1);        priority.add(3);        System.out.println(priority.poll());        System.out.println(priority.poll());    }}

Для стека используйте ArrayDeque, а не устаревший Stack.

Сортировка и Comparator

import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;public class SortDemo {    record Person(String name, int age) {    }    public static void main(String[] args) {        List<Integer> numbers = new ArrayList<>(List.of(5, 2, 8, 1));        Collections.sort(numbers);        System.out.println(numbers);        numbers.sort(Comparator.reverseOrder());        System.out.println(numbers);        List<Person> people = new ArrayList<>(List.of(            new Person("Борис", 30),            new Person("Анна", 25),            new Person("Вера", 25)        ));        people.sort(Comparator.comparingInt(Person::age));        System.out.println(people);        people.sort(Comparator.comparingInt(Person::age).thenComparing(Person::name, Comparator.reverseOrder()));        System.out.println(people);    }}

Класс может сам задать естественный порядок, реализовав Comparable<T>:

public class Version implements Comparable<Version> {    private final int major;    private final int minor;    public Version(int major, int minor) {        this.major = major;        this.minor = minor;    }    @Override    public int compareTo(Version other) {        if (major != other.major) {            return Integer.compare(major, other.major);        }        return Integer.compare(minor, other.minor);    }}

Утилитный класс Collections

import java.util.ArrayList;import java.util.Collections;import java.util.List;public class CollectionsDemo {    public static void main(String[] args) {        List<Integer> list = new ArrayList<>(List.of(4, 2, 9, 1));        System.out.println(Collections.max(list));        System.out.println(Collections.min(list));        Collections.reverse(list);        Collections.shuffle(list);        Collections.swap(list, 0, 1);        System.out.println(Collections.frequency(list, 2));        List<Integer> readOnly = Collections.unmodifiableList(list);        System.out.println(readOnly.size());    }}

Выбор коллекции

  • нужен упорядоченный список с доступом по индексу: ArrayList;
  • нужны уникальные элементы: HashSet, при необходимости порядка — LinkedHashSet или TreeSet;
  • нужен поиск по ключу: HashMap, с сортировкой — TreeMap;
  • нужна очередь или стек: ArrayDeque;
  • нужен приоритет: PriorityQueue.

Объявляйте переменную интерфейсным типом: List<String> list = new ArrayList<>();.