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

Может ли собственный объект быть частью for-each?

1.0 Junior🔥 211 комментариев
#Основы Java

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

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

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

Собственный объект в for-each цикле

Да, можно! Для этого нужно реализовать интерфейс Iterable<T>. Разберу, как это работает и почему.

Основной механизм

For-each цикл в Java — это синтаксический сахар для работы с Iterable:

// Эта запись
for (String item : collection) {
    System.out.println(item);
}

// Развёртывается компилятором в
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
    String item = iterator.next();
    System.out.println(item);
}

Поэтому чтобы объект работал в for-each, он должен реализовать Iterable<T>.

Итерфейс Iterable

public interface Iterable<T> {
    Iterator<T> iterator();
    default void forEach(Consumer<? super T> action) {
        for (T t : this) {
            action.accept(t);
        }
    }
}

Итерфейс Iterator имеет три метода:

public interface Iterator<T> {
    boolean hasNext();
    T next();
    void remove();
}

Пример 1: Простая коллекция чисел

public class NumberRange implements Iterable<Integer> {
    private final int start;
    private final int end;
    
    public NumberRange(int start, int end) {
        this.start = start;
        this.end = end;
    }
    
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            private int current = start;
            
            @Override
            public boolean hasNext() {
                return current < end;
            }
            
            @Override
            public Integer next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                return current++;
            }
        };
    }
}

// Использование
public class Main {
    public static void main(String[] args) {
        NumberRange range = new NumberRange(1, 5);
        
        for (Integer num : range) {
            System.out.println(num);
        }
    }
}

Пример 2: Коллекция студентов

public class Student {
    private String name;
    private int grade;
    
    public Student(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }
    
    @Override
    public String toString() {
        return name + " (" + grade + ")";
    }
}

public class StudentGroup implements Iterable<Student> {
    private final List<Student> students = new ArrayList<>();
    
    public void addStudent(Student student) {
        students.add(student);
    }
    
    @Override
    public Iterator<Student> iterator() {
        return students.iterator();
    }
}

Пример 3: Кастомный Iterator с фильтрацией

public class FilteredList<T> implements Iterable<T> {
    private final List<T> items;
    private final Predicate<T> filter;
    
    public FilteredList(List<T> items, Predicate<T> filter) {
        this.items = items;
        this.filter = filter;
    }
    
    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            private int index = 0;
            
            @Override
            public boolean hasNext() {
                while (index < items.size()) {
                    if (filter.test(items.get(index))) {
                        return true;
                    }
                    index++;
                }
                return false;
            }
            
            @Override
            public T next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                return items.get(index++);
            }
        };
    }
}

Итого

  • For-each работает с любым объектом, реализующим Iterable<T>
  • Нужно реализовать метод iterator(), возвращающий Iterator<T>
  • Iterator имеет три метода: hasNext(), next(), remove()
  • Это позволяет создавать кастомные коллекции с любой логикой обхода