Уявіть, що ви прийшли на склад інтернет-магазину. На одній полиці товари лежать строго в тому порядку, у якому їх привезли. На іншій — кожен предмет унікальний, і дублікати сюди не кладуть за жодних умов. А в кутку стоїть картотека, де кожному товару відповідає унікальний штрих-код.
У світі Java цей склад називається Java Collections Framework (JCF). Це потужний набір інтерфейсів та класів, який дозволяє ефективно керувати групами об’єктів. Проте у початківців часто виникає питання: яку саме структуру даних обрати для вирішення конкретного завдання?
Давайте розберемося з «великою трійкою» JCF — List, Set та Map — раз і назавжди.
1. List (Список): Коли важливий порядок та індекси
List — це впорядкована колекція, елементи якої зберігаються у тій послідовності, у якій ви їх туди додали. Кожен елемент має свій індекс (починаючи з 0), що дозволяє миттєво дістати його за цим номером.
- Особливості: Дозволяє зберігати дублікати (однакові значення) та значення
null. - Найпопулярніші реалізації:
ArrayList: В основі лежить динамічний масив. Ідеально підходить для швидкого доступу до елементів за індексом (O(1)). Проте видалення чи додавання елементів у середину списку працює повільно, бо доводиться зсувати інші елементи.LinkedList: Двозв’язний список, де кожен елемент знає про свого сусіда. Швидко додає та видаляє елементи з початку чи кінця (O(1)), але пошук за індексом вимагає проходу по всьому ланцюжку.
- Коли обирати? Коли вам потрібна стрічка новин, історія повідомлень у чаті, кошик покупок або будь-яка черга, де порядок додавання має першочергове значення.
Життєвий приклад: Список студентів у журналі викладача. Черговість важлива (наприклад, за списком), і цілком можлива ситуація, коли у групі є два студенти з абсолютно однаковими іменами та прізвищами (дублікати).
import java.util.ArrayList;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
// Створюємо список студентів
List<String> students = new ArrayList<>();
// Додаємо елементи (порядок збережеться)
students.add("Олексій");
students.add("Марія");
students.add("Іван");
students.add("Марія"); // Дозволено дублікат!
// Доступ за індексом (швидко)
String firstStudent = students.get(0);
System.out.println("Перший у списку: " + firstStudent); // Олексій
// Виводимо весь список
System.out.println("Весь список студентів: " + students);
// Результат: [Олексій, Марія, Іван, Марія]
}
}Java2. Set (Множина): Боротьба з дублікатами
Set — це колекція, яка моделює математичну множину. Її головне правило: ніяких дублікатів. Якщо ви спробуєте додати елемент, який вже є у множині, колекція просто проігнорує цю дію.
- Особливості: У більшості реалізацій порядок елементів не гарантується.
- Найпопулярніші реалізації:
HashSet: Базується на хеш-таблиці. Забезпечує надзвичайно швидкий пошук, додавання та видалення елементів за константний час (O(1)). Але порядок зберігання хаотичний.LinkedHashSet: Працює майже якHashSet, але запам’ятовує порядок додавання елементів.TreeSet: Зберігає елементи у відсортованому порядку (за зростанням або за допомогою вашого власного правилаComparator). Працює трохи повільніше заHashSetчерез необхідність балансування дерева.
- Коли обирати? Коли потрібно зберігати унікальні дані: список ID користувачів, унікальні IP-адреси відвідувачів сайту, або теги для статті.
Життєвий приклад: Набір тегів під статтею. Немає сенсу писати тег #java двічі під одним постом. Система повинна автоматично відсікати дублікати.
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
// Створюємо множину тегів
Set<String> tags = new HashSet<>();
// Додаємо теги
tags.add("java");
tags.add("spring");
tags.add("programming");
tags.add("java"); // Спроба додати дублікат
// Перевіряємо розмір та вміст
System.out.println("Кількість тегів: " + tags.size()); // Виведе 3, а не 4!
System.out.println("Унікальні теги: " + tags);
// Порядок виведення може бути випадковим: [programming, java, spring]
// Швидка перевірка наявності елемента
if (tags.contains("spring")) {
System.out.println("Тег 'spring' знайдено!");
}
}
}Java3. Map (Карта/Словник): Парами «Ключ — Значення»
Важливо зазначити: хоча Map є частиною фреймворку колекцій Java, цей інтерфейс не успадковується від базового інтерфейсу Collection. Проте концептуально це одна з найважливіших структур. Вона зберігає дані парами: унікальний Ключ та асоційоване з ним Значення.
- Особливості: Ключі мають бути унікальними, тоді як значення можуть дублюватися.
- Найпопулярніші реалізації:
HashMap: Швидкий доступ до значень за ключем (O(1)). Порядок пар не гарантований.LinkedHashMap: Зберігає порядок додавання елементів за ключами.TreeMap: Сортує пари за ключами.
- Коли обирати? Коли потрібно зв’язати дані між собою: телефонна книга (ім’я -> номер), паспортні дані (номер паспорта -> дані людини), або словник (слово -> його переклад).
Життєвий приклад: Кошик в інтернет-магазині. Ключем є унікальний артикул товару (ID), а значенням — кількість штук, яку користувач хоче придбати.
import java.util.HashMap;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
// Створюємо карту (Ключ - ID товару (Integer), Значення - Кількість (Integer))
Map<Integer, Integer> cart = new HashMap<>();
// Додаємо товари до кошика
cart.put(101, 1); // Товар з ID 101 у кількості 1 шт.
cart.put(102, 3); // Товар з ID 102 у кількості 3 шт.
// Оновлюємо значення для існуючого ключа (перезапис)
cart.put(101, 2); // Тепер товару 101 стало 2 шт.
// Отримуємо значення за ключем
int countOfItem102 = cart.get(102);
System.out.println("Кількість товару 102 у кошику: " + countOfItem102); // 3
// Прохід по всій карті (Key-Value)
for (Map.Entry<Integer, Integer> entry : cart.entrySet()) {
System.out.println("Товар ID: " + entry.getKey() + " | Кількість: " + entry.getValue());
}
}
}JavaШпаргалка для вибору: Золоті правила розробника
Щоб не помилитися під час написання коду, ставте собі три прості запитання:
- Чи потрібні мені пари “ключ-значення”? Якщо так — ваш вибір Map (частіше за все
HashMap). - Чи мають дані бути унікальними? Якщо дублікати неприпустимі — використовуйте Set (зазвичай
HashSet). - Чи важливий мені порядок додавання або доступ за номером? Якщо так — обирайте List (найчастіше
ArrayList).
Опанування цих трьох концепцій — це фундамент, на якому будується вся бізнес-логіка сучасних Java-додатків. Пишіть код усвідомлено, обирайте правильні інструменти під ваші завдання, і ваші програми працюватимуть швидко та ефективно!
Зведена порівняльна таблиця для закріплення
| Критерій | List (ArrayList) | Set (HashSet) | Map (HashMap) |
Формат збереження | Поодинокі об’єкти | Поодинокі об’єкти | Пари “Ключ-Значення” |
Допуск дублікатів | Так, дозволено | Ні, тільки унікальні | Ключі — унікальні, Значення — ні |
| Порядок елементів | Зберігається (за індексами) | Переважно хаотичний | Переважно хаотичний |
Головна перевага | Швидкий доступ за номером | Моментальна фільтрація дублікатів | Швидкий пошук значення за його ключем |
Коли ви обираєте інтерфейс List, Set або Map — це лише половина справи. Справжня магія (і головні підводні камені продуктивності) криється в конкретних реалізаціях. Чому ArrayList іноді гальмує? Навіщо потрібен TreeSet, якщо є швидкий HashSet? І коли TreeMap стає незамінним?
Давайте розберемо шість найпопулярніших реалізацій Java Collections Framework на простих життєвих аналогіях та зрозумілих прикладах коду.
1. List: ArrayList проти LinkedList
ArrayList: Динамічний масив (Швидкий доступ)
- Аналогія: Ряд крісел у кінотеатрі. Кожне крісло має чіткий номер. Ви можете миттєво сісти на крісло №5, але якщо захочете вставити нове крісло посередині ряду, усім глядачам праворуч доведеться підвестися й пересісти на одне місце далі.
- Особливості: Швидкий пошук за індексом, але повільне додавання/видалення елементів всередині списку.
- Приклад використання: Список користувачів у системі, який ми часто читаємо і рідко змінюємо.
LinkedList: Двозв’язний список (Швидкі зміни)
- Аналогія: Діти, які тримаються за руки під час прогулянки. Кожна дитина знає лише того, хто стоїть попереду, і того, хто позаду. Щоб вставити нову дитину всередину, достатньо розімкнути одну пару рук і перехопити сусідів. Але щоб знайти 10-ту дитину, вам доведеться рахувати з самого початку.
- Особливості: Швидке додавання та видалення елементів на початку та в кінці, але повільний пошук за індексом.
- Приклад використання: Черга завдань на друк у принтері.
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ListsComparison {
public static void main(String[] args) {
// ArrayList: ідеально для читання
List<String> movieSeats = new ArrayList<>();
movieSeats.add("Крісло 1");
movieSeats.add("Крісло 2");
System.out.println("Швидкий доступ за індексом: " + movieSeats.get(1)); // Крісло 2
// LinkedList: ідеально для динамічних черг
List<String> printQueue = new LinkedList<>();
printQueue.add("Документ_1.pdf");
printQueue.add("Фото.png");
printQueue.add(0, "Терміновий_Договір.pdf"); // Швидка вставка на початок!
System.out.println("Черга друку: " + printQueue);
}
}Java2. Set: HashSet проти TreeSet
HashSet: Швидкість та хаос
- Аналогія: Коробка з унікальними деталями LEGO. Ви можете дуже швидко засунути туди руку і перевірити, чи є там червоний кубик (завдяки магічній математиці хеш-кодів). Але деталі всередині лежать у повному безладі.
- Особливості: Найвища швидкість роботи (
O(1)), порядок елементів випадковий. - Приклад використання: Список унікальних IP-адрес, що відвідали сайт за день.
TreeSet: Ідеальний порядок
- Аналогія: Словник на полиці. Усі слова унікальні та автоматично відсортовані за алфавітом (або числа за зростанням). Шукати слово трохи довше, ніж у коробці, але ви завжди знаєте, що йде після чого.
- Особливості: Працює повільніше за
HashSet(O(log n)), але автоматично сортує всі елементи. - Приклад використання: Таблиця лідерів у грі (усі нікнейми унікальні та відсортовані за рейтингом).
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class SetsComparison {
public static void main(String[] args) {
// HashSet: швидкість без гарантії порядку
Set<String> hashSet = new HashSet<>();
hashSet.add("Яблуко");
hashSet.add("Банан");
hashSet.add("Апельсин");
System.out.println("HashSet (порядок випадковий): " + hashSet);
// Результат може бути: [Банан, Апельсин, Яблуко]
// TreeSet: автоматичне сортування за алфавітом
Set<String> treeSet = new TreeSet<>();
treeSet.add("Яблуко");
treeSet.add("Банан");
treeSet.add("Апельсин");
System.out.println("TreeSet (відсортовано): " + treeSet);
// Результат ЗАВЖДИ: [Апельсин, Банан, Яблук��]
}
}Java3. Maps(Словники): HashMap проти TreeMap
HashMap: Швидкий словник
- Аналогія: Вішалка в гардеробі театру. Ви даєте номерний жетон (ключ) — вам миттєво видають вашу куртку (значення). Номери жетонів не обов’язково йдуть підряд на вішалці, але обмін відбувається миттєво.
- Особливості: Миттєвий доступ до значень за ключем. Порядок ключів не зберігається.
- Приклад використання: База користувачів, де ключ — унікальний
user_id, а значення — об’єктUser.
TreeMap: Сортування за ключами
- Аналогія: Реєстраційна книга в архіві. Кожен запис має унікальний номер (ключ) і опис справи (значення). Усі записи впорядковані строго за зростанням номерів справ, що дозволяє швидко виводити звіти за діапазонами номерів.
- Особливості: Повільніший за
HashMap, але гарантує сортування даних за ключами. - Приклад використання: Звітність компанії, де ключ — дата транзакції, а значення — сума (дозволяє легко отримати транзакції “від дати Х до дати Y”).
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class MapsComparison {
public static void main(String[] args) {
// HashMap: швидкість понад усе
Map<Integer, String> hashMap = new HashMap<>();
hashMap.put(50, "Офіс на 5 поверсі");
hashMap.put(10, "Ресепшн");
hashMap.put(30, "Кафетерій");
System.out.println("HashMap (порядок хаотичний): " + hashMap);
// TreeMap: ключі автоматично сортуються (10, 30, 50)
Map<Integer, String> treeMap = new TreeMap<>();
treeMap.put(50, "Офіс на 5 поверсі");
treeMap.put(10, "Ресепшн");
treeMap.put(30, "Кафетерій");
System.out.println("TreeMap (відсортовано за ключем): " + treeMap);
// Результат: {10=Ресепшн, 30=Кафетерій, 50=Офіс на 5 поверсі}
}
}JavaПідсумкова таблиця для порівняння
| Реалізація | Під капотом | Швидкість пошуку | Чи сортує елементи? | Коли обирати? |
| ArrayList | Динамічний масив | ⚡ Дуже швидко за індексом O(1) | Ні | Потрібно часто читати дані |
| LinkedList | Двозв’язний список | 🐢 Повільно (потрібен перебір) | Ні | Часте додавання/видалення в кінці чи на початку |
| HashSet | Хеш-таблиця | ⚡ Надзвичайно швидко O(1) | Ні | Потрібна максимальна швидкість та унікальність |
| TreeSet | Червоно-чорне дерево | ⚖️ Середня O(log n) | Так, за значенням | Потрібен унікальний відсортований список |
| HashMap | Хеш-таблиця | ⚡ Надзвичайно швидко O(1) | Ні | Потрібно швидко шукати значення за унікальним ключем |
| TreeMap | Червоно-чорне дерево | ⚖️ Середня O(log n) | Так, за ключем | Потрібно зберігати пари та мати сортування за ключами |






