Интерфейс List

List<E> — упорядоченная коллекция, в которой каждый элемент имеет позицию (индекс), начиная с 0. В отличие от Set, список допускает дубликаты и позволяет обращаться к элементам по индексу через get(i)/set(i, e).

Самые популярные реализации:

  • ArrayList — динамический массив. Быстрая случайная выборка (O(1)), медленные вставки/удаления в середине (O(n)).

  • LinkedList — двусвязный список. Быстрая вставка/удаление в концах (O(1)), медленный доступ по индексу (O(n)). Реализует ещё и Deque.

  • Vector/Stack — устаревшие синхронизированные реализации; новый код их избегает.

Иерархия

Collection<E>
    └── List<E>
            ├── ArrayList<E>
            ├── LinkedList<E>   (также Deque<E>)
            └── Vector<E>       (legacy)

Пример 1. ArrayList и доступ по индексу

import java.util.ArrayList;
import java.util.List;

public class ListArrayListDemo {
    public static void main(String[] args) {
        List<String> kits = new ArrayList<>();
        kits.add("Arduino UNO");
        kits.add("Robot Phobo");
        kits.add("ESP32-CAM");

        System.out.println("Первый: " + kits.get(0));
        kits.set(1, "Robot Phobo v2");
        System.out.println("Список: " + kits);
        System.out.println("Индекс ESP32-CAM: " + kits.indexOf("ESP32-CAM"));
    }
}

Output:

Первый: Arduino UNO
Список: [Arduino UNO, Robot Phobo v2, ESP32-CAM]
Индекс ESP32-CAM: 2

Пример 2. Вставка и удаление по индексу

import java.util.ArrayList;
import java.util.List;

public class ListInsertRemove {
    public static void main(String[] args) {
        List<Integer> pins = new ArrayList<>();
        pins.add(2);
        pins.add(5);
        pins.add(6);

        pins.add(1, 4);          // вставить 4 на позицию 1
        System.out.println("После вставки: " + pins);

        pins.remove(0);          // удалить элемент с индексом 0
        System.out.println("После удаления: " + pins);
    }
}

Output:

После вставки: [2, 4, 5, 6]
После удаления: [4, 5, 6]

Пример 3. LinkedList как очередь

import java.util.LinkedList;

public class ListLinkedDemo {
    public static void main(String[] args) {
        LinkedList<String> queue = new LinkedList<>();
        queue.addLast("forward");
        queue.addLast("stop");
        queue.addFirst("init");

        System.out.println("Очередь: " + queue);
        System.out.println("Первая команда: " + queue.pollFirst());
        System.out.println("Осталось: " + queue);
    }
}

Output:

Очередь: [init, forward, stop]
Первая команда: init
Осталось: [forward, stop]

Пример 4. subList — представление диапазона

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ListSubList {
    public static void main(String[] args) {
        List<Integer> data = new ArrayList<>(Arrays.asList(10, 20, 30, 40, 50));
        List<Integer> middle = data.subList(1, 4); // индексы 1..3
        System.out.println("Срез: " + middle);

        middle.set(0, 99); // изменения видны в исходном списке
        System.out.println("Источник: " + data);
    }
}

Output:

Срез: [20, 30, 40]
Источник: [10, 99, 30, 40, 50]

Пример 5. ListIterator — двусторонний обход

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;

public class ListIteratorDemo {
    public static void main(String[] args) {
        List<String> cmds = new ArrayList<>(Arrays.asList("F", "L", "R", "S"));
        ListIterator<String> it = cmds.listIterator();
        while (it.hasNext()) {
            String c = it.next();
            if (c.equals("L")) it.set("LEFT");
        }
        System.out.println("После: " + cmds);
    }
}

Output:

После: [F, LEFT, R, S]

Пример 6. Неизменяемый список

import java.util.List;

public class ListImmutable {
    public static void main(String[] args) {
        List<String> modes = List.of("AUTO", "MANUAL", "LINE");
        System.out.println("Режимы: " + modes);
        try {
            modes.add("X");
        } catch (UnsupportedOperationException ex) {
            System.out.println("Список неизменяемый");
        }
    }
}

Output:

Режимы: [AUTO, MANUAL, LINE]
Список неизменяемый

Подводные камни

  • ArrayList.remove(int) удаляет по индексу, remove(Object) — по значению. С List<Integer> это путает: list.remove(1) удалит индекс 1, а не число 1. Используйте Integer.valueOf(1).

  • subList возвращает представление — изменения отражаются на исходном списке, и наоборот. Структурное изменение исходного списка делает срез невалидным.

  • LinkedList.get(i) — это O(n); для частых обходов используйте итератор.

  • Arrays.asList(...) возвращает список фиксированного размера: add/remove бросят UnsupportedOperationException.

  • List.of(...) запрещает null и любые модификации.

См. также

Примечание

Материал подготовлен на основе официального руководства Oracle The Collections Framework и распространяется на условиях Oracle Free Documentation License. Тексты переписаны своими словами, примеры кода — оригинальные.