Kontrakty Iterable i Iterator
Poznaj interfejsy Iterable i Iterator oraz dowiedz się, jak wewnętrznie działają pętle for-each.
Kontrakty Iterable i Iterator to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
Iterable i Iterator
Iterable<T> i Iterator<T> to interfejsy obsługujące pętlę for-each w języku Java. Ich zrozumienie pozwala tworzyć własne struktury danych zgodne z tą pętlą.
Interfejs Iterable
Iterable<T> ma jedną metodę: iterator(), która zwraca obiekt typu Iterator<T>. Każda klasa implementująca Iterable może być używana w pętli for-each.
// java.lang.Iterable<T>
interface Iterable<T> {
Iterator<T> iterator();
// default: forEach, spliterator (Java 8+)
}
// Any class implementing Iterable<T> works in for-each:
class Range implements Iterable<Integer> {
private final int start, end;
Range(int start, int end) { this.start = start; this.end = end; }
public Iterator<Integer> iterator() {
return new RangeIterator(); // defined separately
}
}Interfejs Iterator
Iterator<T> ma trzy metody: hasNext(), next() oraz opcjonalną remove().
// java.util.Iterator<T>
interface Iterator<T> {
boolean hasNext(); // true if more elements
T next(); // returns next element, advances cursor
default void remove() { throw new UnsupportedOperationException(); }
}
// How for-each desugars internally:
// for (T item : iterable) { use(item); }
// becomes:
Iterator<T> it = iterable.iterator();
while (it.hasNext()) {
T item = it.next();
// use(item)
}Rozwinięcie składni pętli for-each
Pętla for-each jest cukrem składniowym opartym na wzorcu Iterable/Iterator. Zrozumienie tego mechanizmu pomaga poprawnie pisać własne obiekty Iterable.
List<String> names = List.of("Alice", "Bob", "Charlie");
// For-each (readable way)
for (String name : names) {
System.out.println(name);
}
// Equivalent explicit form
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
System.out.println(name);
}Stan kursora iteratora
Iterator przechowuje kursor — pozycję w sekwencji. Wywołanie next() przesuwa kursor do przodu. Po wyczerpaniu iteratora nie można go zresetować.
List<Integer> nums = List.of(1, 2, 3);
Iterator<Integer> it = nums.iterator();
System.out.println(it.hasNext()); // true
System.out.println(it.next()); // 1
System.out.println(it.next()); // 2
System.out.println(it.next()); // 3
System.out.println(it.hasNext()); // false
try {
it.next(); // NoSuchElementException
} catch (java.util.NoSuchElementException e) {
System.out.println("No more elements!");
}ConcurrentModificationException
Modyfikacja kolekcji podczas iterowania za pomocą jawnego iteratora (poza metodą Iterator.remove()) powoduje zgłoszenie wyjątku ConcurrentModificationException.
List<String> list = new ArrayList<>(List.of("a", "b", "c", "d"));
// BAD: modifying collection during for-each
try {
for (String s : list) {
if ("b".equals(s)) list.remove(s); // ConcurrentModificationException!
}
} catch (java.util.ConcurrentModificationException e) {
System.out.println("Cannot modify during iteration!");
}
// GOOD: use Iterator.remove()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if ("b".equals(it.next())) it.remove(); // safe
}
System.out.println(list); // [a, c, d]Wiele iteratorów
Każde wywołanie iterator() zwraca nowy, niezależny iterator. Na tej samej kolekcji może jednocześnie działać wiele iteratorów.
List<Integer> nums = List.of(1, 2, 3);
Iterator<Integer> a = nums.iterator();
Iterator<Integer> b = nums.iterator();
System.out.println(a.next()); // 1
System.out.println(b.next()); // 1 (independent cursor)
System.out.println(a.next()); // 2
System.out.println(b.next()); // 2Iterable a Iterator
Najważniejsze rozróżnienie:
- Iterable: źródło, które może tworzyć iteratory — można po nim iterować wielokrotnie
- Iterator: kursor poruszający się po sekwencji — jednorazowy i przechowujący stan
// Iterable: reusable
List<String> list = List.of("x", "y");
for (String s : list) {} // OK
for (String s : list) {} // OK again — new iterator each time
// Iterator: single-use
Iterator<String> it = list.iterator();
while (it.hasNext()) it.next();
// for (String s : it) {} // compile error — Iterator is not Iterable!Praktyka: własny obiekt Iterable dla wierszy pliku
Czytnik pliku implementujący Iterable, który umożliwia użycie pętli for-each do iterowania po jego wierszach.
import java.io.*;
import java.util.*;
class FileLines implements Iterable<String>, Closeable {
private final BufferedReader reader;
FileLines(String path) throws IOException {
this.reader = new BufferedReader(new FileReader(path));
}
public Iterator<String> iterator() {
return new Iterator<>() {
private String nextLine = readNext();
private String readNext() {
try { return reader.readLine(); }
catch (IOException e) { return null; }
}
public boolean hasNext() { return nextLine != null; }
public String next() {
String curr = nextLine;
nextLine = readNext();
return curr;
}
};
}
public void close() throws IOException { reader.close(); }
}Domyślna metoda forEach
W Java 8 do interfejsu Iterable dodano domyślną metodę forEach(Consumer). Jest to wygodna alternatywa dla pisania jawnych pętli.
List<String> cities = List.of("New York", "London", "Tokyo");
// for-each loop
for (String city : cities) System.out.println(city);
// forEach with lambda
cities.forEach(city -> System.out.println(city));
// forEach with method reference (most concise)
cities.forEach(System.out::println);
// For transforming: use stream
cities.stream()
.map(String::toUpperCase)
.forEach(System.out::println);Wzorzec iteratora w praktyce
Podsumowanie sytuacji, w których warto implementować Iterable/Iterator:
- Niestandardowe struktury danych (drzewa, grafy, listy wiązane)
- Leniwe sekwencje generujące elementy na żądanie
- Sekwencje oparte na zasobach (wiersze pliku, kursor bazy danych, kolejka komunikatów)
Szybkie sprawdzenie
Jaki wyjątek jest zgłaszany podczas modyfikowania kolekcji w trakcie iterowania po niej za pomocą pętli for-each?
Podsumowanie: kontrakty Iterable i Iterator
Najważniejsze informacje:
- Iterable
ma jedną metodę: iterator() — umożliwia obsługę pętli for-each - Iterator
ma metody hasNext(), next() oraz opcjonalną remove() - Pętla for-each jest cukrem składniowym opartym na wzorcu Iterable/Iterator
- Wywołuj iterator() wielokrotnie, aby uzyskać niezależne, nowe kursory
- Nigdy nie modyfikuj kolekcji podczas iterowania za pomocą pętli for-each — zamiast tego używaj Iterator.remove()
- Implementuj Iterable dla własnych struktur danych, aby obsługiwały pętle for-each
Często zadawane pytania
Czy lekcja „Kontrakty Iterable i Iterator” jest bezpłatna?
Tak — pełny tekst „Kontrakty Iterable i Iterator” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Kontrakty Iterable i Iterator”?
Poznaj interfejsy Iterable i Iterator oraz dowiedz się, jak wewnętrznie działają pętle for-each. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Kontrakty Iterable i Iterator”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Kontrakty Iterable i Iterator
- Implementowanie własnego iteratora
- ListIterator i przechodzenie dwukierunkowe
- Iteratory fail-fast a fail-safe