Коллекции и дженерики: List, Set, Map, итераторы и сортировка
В прошлой статье вы познакомились с ООП: классами, объектами, инкапсуляцией, наследованием и полиморфизмом. Но как только в программе появляется много объектов (пользователи, счета, товары, сообщения), сразу возникает практическая задача: где и как их хранить, перебирать, искать и сортировать.
Для этого в Java есть коллекции (Collections Framework) и дженерики (generics), которые делают работу с коллекциями безопасной и удобной.
!Наглядно показывает разницу между List, Set и Map
Что такое коллекции и зачем они нужны
Если нужно хранить несколько значений, первое, что приходит в голову, это массив.
Но у массивов есть ограничения:
размер нужно знать заранее (или создавать новый массив и копировать)
неудобно вставлять и удалять элементы
нет готовых удобных операций вроде поиска, проверки уникальности, хранения пар ключ-значениеКоллекции решают эти проблемы: они умеют динамически расти, предоставляют готовые структуры данных и методы.
Официальная справка: Collections Framework Overview
Дженерики: почему List<String> лучше, чем просто List
Дженерики позволяют указать, какой тип элементов хранится в коллекции.
Пример:
Что дают дженерики:
безопасность типов: нельзя случайно положить в List<String> число
меньше ошибок во время выполнения: больше проверок происходит при компиляции
не нужно делать приведения типа (не нужен (String))Плохой (устаревший) стиль, который лучше не использовать:
С дженериками Java не даст так написать.
Документация: Generics (Java Tutorials)
List: упорядоченная коллекция с доступом по индексу
List хранит элементы:
в определенном порядке (как вы добавляли)
допускает повторы
позволяет получать элемент по индексу: get(0), get(1)Основные реализации:
ArrayList: самый популярный вариант для начинающих
LinkedList: используется реже, в специфических задачахДокументация: List
Основные операции с List
Полезные методы:
add(value)
get(index)
set(index, value)
remove(index) или remove(value)
size()
contains(value)Перебор List: цикл for-each
Самый простой способ пройтись по элементам:
Это читается как: для каждого элемента t в списке tasks.
List с объектами (связь с ООП)
Вы можете хранить в списке не только строки, но и свои объекты.
Set: коллекция без повторов
Set хранит элементы так, что одинаковых значений быть не может.
порядок может быть не таким, как при добавлении (зависит от реализации)
повторы не допускаютсяЧастые реализации:
HashSet: самый популярный, порядок не гарантируется
LinkedHashSet: сохраняет порядок добавления
TreeSet: хранит в отсортированном видеДокументация: Set
Пример HashSet
Важная идея: как Set понимает, что элементы одинаковые
Для строк (String) все работает ожидаемо, потому что String уже умеет сравнивать значения.
Для ваших классов важно, чтобы Java могла понять, что два объекта равны по смыслу. Для этого используют методы equals() и hashCode().
На старте запомните простое правило:
если вы кладете свои объекты в HashSet (или используете их как ключи в HashMap), то вам почти всегда нужно корректно переопределить equals() и hashCode()Документация: Object.equals) и Object.hashCode)
Map: хранение пар ключ-значение
Map хранит пары:
ключ (key)
значение (value)Ключи уникальны. Значения могут повторяться.
Пример: по email быстро находить пользователя.
Документация: Map
Пример HashMap
Полезные методы:
put(key, value)
get(key)
containsKey(key)
remove(key)
keySet() (все ключи)
values() (все значения)
entrySet() (все пары ключ-значение)Перебор Map через entrySet()
Это самый удобный способ, когда нужны и ключ, и значение.
Итераторы: как коллекции перебираются внутри
Вы уже использовали for-each. Под капотом он часто работает через итератор.
Итератор это объект, который умеет идти по коллекции шаг за шагом.
Документация: Iterator
Зачем итератор нужен новичку
Самая частая практическая причина: нужно удалять элементы во время перебора.
Неправильный вариант (часто приводит к ошибке во время выполнения):
Правильный вариант: использовать Iterator и его remove().
Здесь:
hasNext() проверяет, есть ли следующий элемент
next() возвращает следующий элемент
remove() безопасно удаляет текущий элементСортировка: Comparable, Comparator и сортировка списков
Сортировка чаще всего применяется к List.
Есть два основных подхода:
объект сам знает, как его сортировать: Comparable
вы задаете правило сортировки снаружи: ComparatorДокументация: Comparable и Comparator
Сортировка простых типов
Строки и числа сортируются сразу.
Документация: Collections
Comparator: сортировка объектов по правилу
Допустим, у нас есть счета, и мы хотим сортировать их по балансу.
Здесь:
accounts.sort(...) сортирует список на месте
Comparator.comparingInt(...) задает правило: сравнивать по целому числуСортировка по убыванию
Когда нужен Comparable
Если у вашего класса есть естественный порядок (например, деньги, даты, номера), можно реализовать Comparable.
Идея: класс сам определяет, как сравнивать два объекта.
Пример (упрощенный): сортировка аккаунтов по владельцу.
На практике, когда вы только начинаете, чаще удобнее использовать Comparator, потому что он не заставляет менять класс.
Как выбрать структуру: короткая памятка
| Что нужно | Подходит | Почему |
|---|---|---|
| Хранить элементы в порядке добавления, разрешить повторы, брать по индексу | List (ArrayList) | Упорядоченно, есть индекс |
| Хранить только уникальные значения | Set (HashSet) | Дубликаты не добавляются |
| Быстро находить значение по ключу | Map (HashMap) | Доступ через ключ |
Типичные ошибки новичка
Используют коллекции без дженериков (List list = ...) и получают ошибки приведения типа
Пытаются удалять элементы из List внутри for-each вместо Iterator.remove()
Ожидают, что HashSet или HashMap будут хранить элементы в том же порядке, что и добавление
Сортируют объекты без Comparator или Comparable и удивляются, что Java не знает, как сравниватьИтог
Теперь у вас есть базовый набор для работы с множеством данных:
дженерики для безопасных коллекций: List<BankAccount>, Map<String, Integer>
List для упорядоченных данных и доступа по индексу
Set для уникальных значений
Map для связки ключ-значение
итераторы для корректного перебора и безопасного удаления
сортировка через Comparator и ComparableС этими инструментами вы можете писать программы, которые хранят и обрабатывают реальные наборы объектов: пользователей, заказы, товары, счета и многое другое.