JavaRush /Курси /JAVA 25 SELF /List: ArrayList і LinkedList, основні операції

List: ArrayList і LinkedList, основні операції

JAVA 25 SELF
Рівень 26 , Лекція 1
Відкрита

1. Клас ArrayList

У Java інтерфейс List — це контракт: «Я — впорядкована колекція елементів, з якої можна отримати елемент за номером (індексом)».

Ключові властивості списку (List):

  • Елементи зберігаються у певному порядку (на відміну від множини).
  • Можна зберігати дублікати елементів (наприклад: двічі "Андрій").
  • Можна звернутися до елемента за індексом: перший елемент — індекс 0, другий — 1 і так далі.
  • Можна додавати й видаляти елементи в будь-яке місце списку.

Найпопулярніша реалізація інтерфейсу List — це ArrayList. Усередині він використовує звичайний масив і автоматично збільшує розмір зі зростанням даних.

Як створити ArrayList?

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

public class Example {
    public static void main(String[] args) {
        // Створюємо список рядків
        List<String> students = new ArrayList<>();
    }
}

Пояснення

  • List<String> — це змінна типу «список рядків». Змінну оголошуємо за інтерфейсом, а об’єкт створюємо конкретним класом (ArrayList).
  • Кутові дужки <String> задають тип елементів списку — дженерики (generics).

Основні методи ArrayList (і взагалі будь-якого List):

  • add(element) — додати елемент у кінець списку.
  • add(index, element) — вставити елемент за конкретним індексом.
  • get(index) — отримати елемент за індексом.
  • set(index, element) — замінити елемент за індексом.
  • remove(index) — видалити елемент за індексом.
  • remove(Object) — видалити перший знайдений елемент, що дорівнює переданому об’єкту.
  • size() — дізнатися кількість елементів у списку.

Приклад: Працюємо зі списком студентів

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

public class StudentListDemo {
    public static void main(String[] args) {
        List<String> students = new ArrayList<>();

        // Додаємо студентів
        students.add("Андрій");
        students.add("Петро");
        students.add("Марія");

        // Виводимо всіх студентів
        System.out.println("Список студентів: " + students);

        // Отримуємо першого студента
        String first = students.get(0);
        System.out.println("Перший студент: " + first);

        // Змінюємо імʼя другого студента
        students.set(1, "Павло");
        System.out.println("Після зміни: " + students);

        // Видаляємо Марію
        students.remove("Марія");
        System.out.println("Після видалення Марії: " + students);

        // Розмір списку
        System.out.println("Усього студентів: " + students.size());
    }
}

Результат:

Список студентів: [Андрій, Петро, Марія]
Перший студент: Андрій
Після зміни: [Андрій, Павло, Марія]
Після видалення Марії: [Андрій, Павло]
Усього студентів: 2

Як це пов’язано з вашим застосунком?
Припустімо, що у вас є застосунок для обліку студентських завдань. Ви можете зберігати список завдань як List<String>, а не як масив, і динамічно додавати нові записи.

2. Клас LinkedList: коли важлива швидкість вставлення та видалення

LinkedList — альтернативна реалізація списку. Влаштований як двозвʼязний ланцюжок: кожен вузол знає попередній і наступний елементи. Як у складі потяга: вставити «вагон» посередині можна швидко й без перебудови всього складу.

Створення LinkedList

import java.util.LinkedList;
import java.util.List;

public class Example {
    public static void main(String[] args) {
        List<String> tasks = new LinkedList<>();
    }
}

Особливості LinkedList

  • Швидке вставлення та видалення на початку й у середині списку.
  • Повільний доступ за індексом (щоб знайти 100-й елемент, потрібно пройтися ланцюжком).
  • Підходить, якщо ви часто додаєте або видаляєте елементи не лише в кінець, а й на початок чи в середину.

Приклад: Використовуємо LinkedList

import java.util.LinkedList;
import java.util.List;

public class TaskListDemo {
    public static void main(String[] args) {
        List<String> tasks = new LinkedList<>();

        tasks.add("Прокинутися");
        tasks.add("Поснідати");
        tasks.add("Піти на пари");

        // Додаємо завдання на початок
        tasks.add(0, "Поставити будильник");

        System.out.println("Список завдань: " + tasks);

        // Видаляємо перше завдання (найраніше)
        tasks.remove(0);

        System.out.println("Після видалення першого завдання: " + tasks);
    }
}

3. Порівняння ArrayList і LinkedList

Критерій
ArrayList
LinkedList
Основа Масив Двозвʼязний список
Швидкий доступ за індексом Так (O(1)) Ні (O(n))
Швидке вставлення/видалення на початку/у середині Ні (O(n)) Так (O(1) — якщо є посилання)
Швидке вставлення/видалення в кінці Так (зазвичай O(1)) Так (O(1))
Памʼять Споживає менше памʼяті Більше (через додаткові посилання на сусідів)
Типові завдання Частий доступ за індексом Часті вставлення/видалення

Просте правило:

  • Потрібен швидкий доступ за індексом — використовуйте ArrayList.
  • Часто додаєте або видаляєте на початку чи в середині — використовуйте LinkedList.

4. Типові операції зі списками

Перебирання елементів списку

Звичайний цикл for

for (int i = 0; i < students.size(); i++) {
    System.out.println("Студент №" + i + ": " + students.get(i));
}

Цикл for-each (найпопулярніший спосіб)

for (String name : students) {
    System.out.println("Імʼя: " + name);
}

Лямбда-вираз (Java 8+)

students.forEach(name -> System.out.println("Імʼя: " + name));

Пошук елементів

  • contains(element) — повертає true, якщо елемент є у списку.
  • indexOf(element) — повертає індекс першого входження елемента або -1, якщо не знайдено.
if (students.contains("Андрій")) {
    System.out.println("Андрій є у списку!");
}
int index = students.indexOf("Андрій");
System.out.println("Індекс Андрія: " + index);

Очищення списку

clear() — видаляє всі елементи.

students.clear();
System.out.println("Список після очищення: " + students);

5. Коли використовувати ArrayList, а коли LinkedList?

Зручно мислити так: ArrayList доречний там, де потрібно швидко звертатися до елементів за індексом і список змінюється нечасто. Наприклад, великий список користувачів або історія повідомлень — переважно читання.

LinkedList, навпаки, корисний, коли постійно вставляєте або видаляєте елементи на початку чи у середині. Це може бути черга, стек або історія скасування дій.

На практиці найчастіше використовують ArrayList, а LinkedList радше інструмент «на всяк випадок»: лежить у шухляді, але іноді саме він і потрібен.

6. Типові помилки під час роботи зі списками

Помилка № 1: Вихід за межі списку. Найпоширеніша ситуація — звернення за неіснуючим індексом. Якщо список із трьох елементів, а ви пишете students.get(5), отримаєте IndexOutOfBoundsException. Перед доступом перевіряйте size().

Помилка № 2: Видалення елемента під час перебору. Під час перебору через for-each і одночасного видалення елементів виникне ConcurrentModificationException. Для складних видалень використовуйте цикл за індексом або Iterator.

Помилка № 3: Неправильне порівняння об’єктів. Якщо ви зберігаєте власні об’єкти (наприклад, Student), методи contains і remove спираються на equals. Якщо його не перевизначити, порівняння буде за посиланням, а не за вмістом.

Помилка № 4: Використання сирих типів. Не пишіть List list = new ArrayList() — завжди вказуйте тип елементів: List<String> list = new ArrayList<>(). Дженерики захищають від помилок і роблять код зрозумілішим.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ