Iterator и Iterable

Тема дорожной карты · Java

Итераторы в Java — это объекты, реализующие интерфейс java.util.Iterator<E> и предоставляющие единообразный, безопасный способ обхода любой структуры данных Java Collections Framework по одному элементу за раз, не раскрывая её внутреннего представления. Контракт Iterator состоит из трёх методов: hasNext() возвращает true, если остались ещё элементы, next() продвигает курсор и возвращает текущий элемент, а remove() удаляет последний возвращённый элемент из базовой коллекции — единственный безопасный способ удалять элементы во время итерации, поскольку прямой вызов Collection.remove() внутри расширенного цикла for-each бросает ConcurrentModificationException. Расширенный цикл for-each (for (String s : list)) — это синтаксический сахар, который компилятор превращает в явный цикл с Iterator, используя интерфейс Iterable<E>: любой класс, реализующий Iterable, можно итерировать таким образом, включая все Collections, массивы и пользовательские доменные объекты. ListIterator<E> расширяет Iterator двунаправленным обходом (hasPrevious(), previous()) и заменой на месте (set()), что полезно для алгоритмов, требующих сканирования List в обоих направлениях. Итераторы Java стали менее заметны со Stream API (Java 8+), заменившим императивные циклы с итераторами декларативными конвейерами filter, map и reduce, однако понимание итераторов Java остаётся обязательным для реализации пользовательских Iterable-структур данных, написания низкоуровневых адаптеров коллекций и отладки сбоев ConcurrentModificationException в многопоточных сценариях Java Concurrency.

Как это работает

Iterator и Iterable даёт List (ArrayList, LinkedList), Set (HashSet, TreeSet, LinkedHashSet), Map (HashMap, TreeMap, LinkedHashMap, ConcurrentHashMap), Queue (ArrayDeque, PriorityQueue). Все реализуют Collection (Map отдельно). Streams API (stream(), filter(), map(), collect()) заменяет большинство явных циклов. Immutable factory-методы: List.of(...), Map.of(...), Set.of(...) — возвращают read-only view (бросают при мутации).

Когда применять

ArrayList по умолчанию вместо LinkedList — array-backed доступ драматически быстрее для почти любой реальной нагрузки. HashMap — кроме случаев, где важен порядок (LinkedHashMap для insertion order, TreeMap для sorted). ConcurrentHashMap — для shared-state map (никогда не оборачивайте HashMap в Collections.synchronizedMap в новом коде). Stream — для трансформаций; циклы — для side-effect-обработки.

Типичные ошибки

Ловушки Iterator и Iterable: выбор LinkedList для "быстрых insert" без замеров (cache-miss затмевает алгоритмическое преимущество); Map<String, ...> с mutable ключевыми объектами (hashCode меняется — потерянные entry); List.of(...) и попытка добавить позже (UnsupportedOperationException); concurrent modification в for-цикле (CME — используйте removeIf или Iterator).

Связанные понятия

Полезные ресурсы