← Назад к вопросам

Что должен имплементировать класс для использования его объектов в For Each

2.0 Middle🔥 141 комментариев
#Коллекции#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Класс должен имплементировать интерфейс Iterable

Для использования объекта в for-each loop (enhanced for statement) класс ОБЯЗАТЕЛЬНО должен реализовать интерфейс Iterable<T> или наследоваться от класса, который его реализует.

Структура Iterable

public interface Iterable<T> {
    // Единственный метод
    Iterator<T> iterator();
}

Класс должен реализовать метод iterator(), который возвращает объект Iterator<T>.

Iterator интерфейс

public interface Iterator<T> {
    // Проверяет, есть ли следующий элемент
    boolean hasNext();
    
    // Возвращает следующий элемент
    T next();
    
    // Опционально: удаление текущего элемента
    void remove();
}

Минимальная реализация

import java.util.Iterator;

public class SimpleList<T> implements Iterable<T> {
    private Object[] items = new Object[10];
    private int size = 0;
    
    public void add(T item) {
        items[size++] = item;
    }
    
    @Override
    public Iterator<T> iterator() {
        return new SimpleIterator();
    }
    
    // Приватный класс-итератор
    private class SimpleIterator implements Iterator<T> {
        private int index = 0;
        
        @Override
        public boolean hasNext() {
            return index < size;
        }
        
        @Override
        public T next() {
            return (T) items[index++];
        }
    }
    
    // Теперь можно использовать в for-each
    public static void main(String[] args) {
        SimpleList<String> list = new SimpleList<>();
        list.add("Java");
        list.add("Python");
        list.add("C++");
        
        for (String lang : list) {  // ✅ Работает!
            System.out.println(lang);
        }
    }
}

Полный пример с правильной реализацией

import java.util.Iterator;
import java.util.NoSuchElementException;

public class CustomList<T> implements Iterable<T> {
    private Node<T> head;
    private int size;
    
    public void add(T value) {
        if (head == null) {
            head = new Node<>(value);
        } else {
            Node<T> current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = new Node<>(value);
        }
        size++;
    }
    
    @Override
    public Iterator<T> iterator() {
        return new CustomIterator(head);
    }
    
    // Узел связного списка
    private static class Node<T> {
        T value;
        Node<T> next;
        
        Node(T value) {
            this.value = value;
        }
    }
    
    // Реализация Iterator
    private class CustomIterator implements Iterator<T> {
        private Node<T> current;
        
        CustomIterator(Node<T> head) {
            this.current = head;
        }
        
        @Override
        public boolean hasNext() {
            return current != null;
        }
        
        @Override
        public T next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            T value = current.value;
            current = current.next;
            return value;
        }
        
        @Override
        public void remove() {
            // Опционально: реализовать удаление
        }
    }
    
    public static void main(String[] args) {
        CustomList<Integer> numbers = new CustomList<>();
        numbers.add(10);
        numbers.add(20);
        numbers.add(30);
        
        // Используем в for-each
        for (Integer num : numbers) {
            System.out.println(num);
        }
    }
}

Как устроен For-Each под капотом

// For-each:
for (String item : list) {
    System.out.println(item);
}

// Компилируется в эквивалент:
for (Iterator<String> iterator = list.iterator(); 
     iterator.hasNext(); ) {
    String item = iterator.next();
    System.out.println(item);
}

Итератор как отдельный класс

import java.util.Iterator;

public class MyCollection<T> implements Iterable<T> {
    private T[] items;
    private int size;
    
    public MyCollection(int capacity) {
        items = (T[]) new Object[capacity];
        size = 0;
    }
    
    public void add(T item) {
        items[size++] = item;
    }
    
    @Override
    public Iterator<T> iterator() {
        return new MyIterator();  // Возвращаем новый экземпляр
    }
    
    // Публичный внешний класс
    public class MyIterator implements Iterator<T> {
        private int index = 0;
        
        @Override
        public boolean hasNext() {
            return index < size;
        }
        
        @Override
        public T next() {
            return items[index++];
        }
    }
}

Встроенные примеры в Java

Все встроенные коллекции реализуют Iterable:

// Все эти классы реализуют Iterable
List<String> list = new ArrayList<>();
Set<Integer> set = new HashSet<>();
Queue<String> queue = new LinkedList<>();

// Поэтому все работают с for-each
for (String s : list) { }
for (Integer i : set) { }
for (String s : queue) { }

Анонимный итератор

public class SimpleIterable<T> implements Iterable<T> {
    private T[] items;
    private int size;
    
    public SimpleIterable(int capacity) {
        items = (T[]) new Object[capacity];
    }
    
    public void add(T item) {
        items[size++] = item;
    }
    
    @Override
    public Iterator<T> iterator() {
        // Анонимный класс
        return new Iterator<T>() {
            private int index = 0;
            
            @Override
            public boolean hasNext() {
                return index < size;
            }
            
            @Override
            public T next() {
                return items[index++];
            }
        };
    }
}

Java 8+: Stream вместо Iterator

public class ModernCollection<T> implements Iterable<T> {
    private java.util.List<T> items = new java.util.ArrayList<>();
    
    public void add(T item) {
        items.add(item);
    }
    
    @Override
    public Iterator<T> iterator() {
        return items.iterator();  // Делегируем ArrayList
    }
    
    // Используем в for-each
    public static void main(String[] args) {
        ModernCollection<String> collection = new ModernCollection<>();
        collection.add("a");
        collection.add("b");
        
        // For-each
        for (String s : collection) {
            System.out.println(s);
        }
    }
}

Ошибка при отсутствии Iterable

public class NonIterable {
    private int[] values = {1, 2, 3};
}

// Ошибка при попытке использовать for-each:
NonIterable ni = new NonIterable();
for (int v : ni) {  // ❌ COMPILE ERROR!
    // Cannot resolve symbol 'iterator'
}

Чек-лист для реализации Iterable

  1. Реализовать интерфейс Iterable<T>
  2. Переопределить метод iterator()Iterator<T>
  3. Создать класс, реализующий Iterator<T> (внутренний или отдельный)
  4. Реализовать методы hasNext() и next()
  5. Опционально: реализовать remove()
  6. Обработать NoSuchElementException когда итератор закончился

Заключение

Для использования объекта в for-each:

  • Класс должен реализовать Iterable<T>
  • Метод iterator() возвращает Iterator<T>
  • Iterator имплементирует hasNext() и next()
  • For-each синтаксис сахар вокруг Iterator pattern
  • Все встроенные коллекции (List, Set, Queue) уже реализуют это