Iterable- ja Iterator-sopimukset
Ymmärrä Iterable- ja Iterator-rajapinnat sekä se, miten for-each-silmukat toimivat sisäisesti.
Iterable- ja Iterator-sopimukset on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.
Iterable ja Iterator
Iterable<T> ja Iterator<T> ovat rajapinnat, joiden varaan Javan for-each-silmukka rakentuu. Niiden ymmärtäminen auttaa tekemään omista tietorakenteistanne silmukkayhteensopivia.
Iterable-rajapinta
Iterable<T>-rajapinnassa on yksi metodi: iterator(), joka palauttaa Iterator<T>-olion. Mitä tahansa Iterable-rajapinnan toteuttavaa luokkaa voi käyttää for-each-silmukassa.
// 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
}
}Iterator-rajapinta
Iterator<T>-rajapinnassa on kolme metodia: hasNext(), next() ja valinnainen 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)
}For-each-silmukan purkaminen
For-each-silmukka on Iterable/Iterator-mallin syntaktista sokeria. Tämän ymmärtäminen auttaa kirjoittamaan mukautetut Iterable-toteutukset oikein.
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);
}Iteratorin kursorin tila
Iterator ylläpitää kursoria eli sijaintia sekvenssissä. next()-kutsun tekeminen siirtää kursoria eteenpäin. Kun iterator on käyty loppuun, sitä ei voi palauttaa alkutilaan.
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
Kokoelman muokkaaminen iteroinnin aikana eksplisiittistä iteratoria käyttäen (muutoin kuin Iterator.remove()-kutsulla) aiheuttaa poikkeuksen 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]Useita iteraattoreita
Jokainen iterator()-kutsu palauttaa uuden, itsenäisen iteraattorin. Samassa kokoelmassa voi olla samanaikaisesti aktiivisia useita iteraattoreita.
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 ja Iterator
Keskeinen ero:
- Iterable: lähde, joka voi tuottaa iteraattoreita — voidaan iteroida useita kertoja
- Iterator: sekvenssin kursori — kertakäyttöinen ja tilallinen
// 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!Käytännön harjoitus: mukautettu tiedoston rivien Iterable
Tiedostonlukija, joka toteuttaa Iterable-rajapinnan ja mahdollistaa tiedoston rivien läpikäynnin for-each-silmukalla.
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(); }
}forEach-oletusmetodi
Java 8 lisäsi Iterable-rajapintaan oletusmetodin forEach(Consumer). Se on kätevä vaihtoehto eksplisiittisten silmukoiden kirjoittamiselle.
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);Iterator-malli käytännössä
Yhteenveto tilanteista, joissa Iterable/Iterator kannattaa toteuttaa:
- Mukautetut tietorakenteet, kuten puu, graafi tai linkitetty lista
- Laiskat sekvenssit, jotka tuottavat alkioita tarpeen mukaan
- Resurssipohjaiset sekvenssit, kuten tiedoston rivit, tietokantakursori tai viestijono
Pikatarkistus
Mikä poikkeus aiheutuu, kun kokoelmaa muokataan for-each-silmukalla iteroinnin aikana?
Kertaus: Iterable- ja Iterator-sopimukset
Tärkeimmät opit:
- Iterable
:llä on yksi metodi: iterator() — mahdollistaa for-each-silmukan käytön - Iterator
:llä on metodit hasNext(), next() ja valinnainen remove() - For-each-silmukka on Iterable/Iterator-mallin syntaktista sokeria
- Kutsu iterator()-metodia useita kertoja saadaksesi toisistaan riippumattomat uudet kursorit
- Älä koskaan muokkaa kokoelmaa for-each-silmukan aikana — käytä sen sijaan Iterator.remove()-metodia
- Toteuta mukautetuille tietorakenteille Iterable, jotta ne tukevat for-each-silmukoita
Opi Java tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 104
- Oppitunnit
- 374
Usein kysytyt kysymykset
Onko oppitunti ”Iterable- ja Iterator-sopimukset” ilmainen?
Kyllä – oppitunnin ”Iterable- ja Iterator-sopimukset” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Iterable- ja Iterator-sopimukset”?
Ymmärrä Iterable- ja Iterator-rajapinnat sekä se, miten for-each-silmukat toimivat sisäisesti. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.
Kuinka kauan ”Iterable- ja Iterator-sopimukset”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?
Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Iterable- ja Iterator-sopimukset
- Mukautetun iteraattorin toteuttaminen
- ListIterator ja kaksisuuntainen läpikäynti
- Fail-fast- ja fail-safe-iteraattorit