Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

I kode-eksemplet over er uttrykket som fremskaffer iteratoren utelatt, så hvor kommer så iteratorene fra? Siden det vanligvis er en tett kobling mellom implementasjonen av data-kilden og den tilhørende iteratoren, er det vanlig at det nettopp er datakilden som kan levere en iterator. F.eks. har begge de to standard List-implementasjonene ArrayList og LinkedList en iterator()-metode som returnerer en Iterator-implementasjon for sine data. Iteratoren for en ArrayList vil være ulik iteratoren for en LinkedList, men oppførselen vil være den samme: Den lar deg gå gjennom elementene med next(), så lenge hasNext() returnerer true. Faktisk er det å kunne levere en iterator så viktig for samlinger av objekter, at iterator()-metoden er definert i alle Collection-grensesnittet, som List bygger påimplementasjoner har en slik metode, og (siden List utvider Collection) dermed også alle List-implementasjoner. Dette betyr at alle Collection-objekter, støtter iterator-basert iterasjon, slik at vi hver gang vi trenger å løpe gjennom elementene i en Collection, kan bruke en iterator.

java.lang.Iterable-grensesnittet

Den vanlige måten å gå gjennom en liste med elementer er med kode som den under til venstre. Dette kalles en for-each-løkke, fordi den går gjennom hvert element i lista. Dette er egentlig spesial-syntaks for iterator-basert iterasjon, det er bare det at du aldri ser iteratoren. Funksjonelt sett er for-each-løkka til venstre ekvivalent med den Iterator-baserte løkka under til høyre. Det er egentlig en smaksak hvilken en bruker, men den venstre varianten er å foretrekke fordi den både er enklere å skrive og lese.

...

Hvis en tenker over det, så er det nettopp iterator()-metoden, som er nøkkelen til at for-each-løkka virker. Det holder at stringListe i kode-eksemplet har en slik metode, for at den skal kunne "omskrives" til koden til høyre som den tilsvarer. Denne koblingen mellom for-each-løkka og iterator()-metoden er ikke tilfeldig, og for å gjøre koblingen eksplisitt og mulig å utnytte for klasser utenfor Collection-rammeverket, så er iterator()-metoden definert i et eget grensesnitt ved navn Iterable (i java.lang-pakken, så en slipper egen import-setning). Det er altså fordi en ArrayList implementerer Iterable at en for-each-løkke med en ArrayList virker! Og ArrayList implementerer Iterable fordi den implementerer List, og List utvider Collection som utvider Iterable. Denne koblingen mellom ArrayList og Iterable er illustrert under med et klassediagram:

PlantUML Macro
interface "Iterable<T>" as iterable {
	Iterator<T> iterator()
}
interface "Collection<T>" as collection
interface "List<T>" as list
class "ArrayList<T>" as arraylist
class "LinkedList<T>" as linkedlist

collection <|-- iterable
list <|-- collection
arraylist <|.. list
linkedlist <|.. list

 

 

En Iterator for en Library-klasse kan se slik ut:

Code Block
languagejava
// OBS: Merk at metodene i denne klassen er uferdige. Logikken i hver metode vil avhenge av hvordan Library-klassen er.
 
import java.util.Iterator;

public class LibraryIterator implements Iterator<Book> {
	private Library library;
	// Eventuelle andre tilstander for å holde styr på iterasjonen
	
	public LibraryIterator(Library library) {
		this.library = library;
		// Sett eventuelle andre tilstander
	}
 
	public boolean hasNext() {
		boolean hasNext = false;
		// Kode for å sjekke om Library har flere Book-objekter
		return hasNext;
	}
 
	public Book next() {
		// Returner neste Book i Library
		return book;
	}
 
	public void remove() {
		// Kode for å fjerne sist returnerte bok eller la stå tom
	}
}

Iterable-grensesnittet

Når et objekt implementerer Iterable-grensesnittet sikrer man at det er mulig å iterere over objektet. Et Iterable<type>-objekt trenger kun å implementere én metode:

...