Iterable în Java

Interfața care permite bucla for-each: orice obiect Iterable poate fi parcurs cu for (T x : obiect) și cu forEach.

Sintaxă
import java.lang.Iterable;   // nu trebuie importat

public interface Iterable<T> {
    Iterator<T> iterator();
    default void forEach(Consumer<? super T> action)
}

Ce face Iterable

Iterable (din java.lang, deci fără import) are o singură metodă obligatorie: iterator(). Orice clasă care o implementează poate fi folosită în bucla for (T x : obiect). Toate colecțiile (List, Set, Queue) sunt Iterable.

forEach(actiune) apelează acțiunea pentru fiecare element, în ordinea dată de iterator. Este echivalent cu un for-each, dar scris ca lambda sau referință la metodă: lista.forEach(System.out::println).

Poți face și propriile clase Iterable: implementezi iterator() și obiectul tău merge direct în for-each.

Parametri

Parametru Descriere
action Pentru forEach: ce se face cu fiecare element (un Consumer).

Ce returnează

iterator() returnează un Iterator<T>; forEach nu returnează nimic.

Exemple

Exemplul 1: forEach pe o listă și pe o mulțime

import java.util.List;
import java.util.TreeSet;

public class Main {
    public static void main(String[] args) {
        List<String> orase = List.of("Iași", "Cluj", "Sibiu");
        orase.forEach(System.out::println);

        TreeSet<Integer> note = new TreeSet<>(List.of(10, 7, 9));
        note.forEach(n -> System.out.println("Notă: " + n));
    }
}

Rezultat

Iași
Cluj
Sibiu
Notă: 7
Notă: 9
Notă: 10

Exemplul 2: O clasă proprie care merge în for-each

Clasa Interval implementează Iterable<Integer>, deci poate fi parcursă cu for-each și cu forEach.

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

public class Main {
    record Interval(int de, int pana) implements Iterable<Integer> {
        public Iterator<Integer> iterator() {
            return new Iterator<>() {
                int curent = de;

                public boolean hasNext() {
                    return curent <= pana;
                }

                public Integer next() {
                    if (!hasNext()) {
                        throw new NoSuchElementException();
                    }
                    return curent++;
                }
            };
        }
    }

    public static void main(String[] args) {
        for (int zi : new Interval(1, 5)) {
            System.out.print("ziua " + zi + "  ");
        }
        System.out.println();
        new Interval(8, 10).forEach(ora -> System.out.println("Ora " + ora + ":00"));
    }
}

Rezultat

ziua 1  ziua 2  ziua 3  ziua 4  ziua 5  
Ora 8:00
Ora 9:00
Ora 10:00

Greșeli frecvente

  • Modifici colecția (adaugi sau ștergi) în interiorul lui forEach sau al unui for-each. Apare ConcurrentModificationException; folosește removeIf sau un Iterator.
  • Încerci break sau return din lambda lui forEach ca să oprești bucla. return sare doar peste elementul curent; pentru oprire folosește un for-each obișnuit.

Comenzi înrudite

  • Iterator: Obiectul care parcurge o colecție element cu element: hasNext() întreabă dacă mai urmează ceva, next() îl dă pe următorul.
  • Collection: Interfața de bază pentru liste, mulțimi și cozi: metodele comune add, remove, contains, size și parcurgerea cu for-each.
  • Map.forEach: Parcurge toate perechile unui map și apelează o funcție cu cheia și valoarea fiecăreia: map.forEach((k, v) -> …).
  • List.iterator: iterator parcurge lista înainte; listIterator poate merge și înapoi, poate înlocui și insera elemente.
  • List.spliterator: Returnează un Spliterator: un iterator care se poate împărți în bucăți, folosit de stream-uri pentru prelucrare în paralel.