Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

  • boolean hasNext() - returnerer true hvis det er flere elementer igjen av sekvensen av elementer og false ellers. Denne metoden kan kalles mange ganger uten at det endrer hvor langt en er kommet.
  • <type> next() - returnerer neste element i sekvensen og tar implisitt et steg videre. Returtypen er typen som Iterator-implementasjonen er spesialisert til. Denne metoden kan bør bare kalles dersom hasNext() returnerer truehvis den kalles når hasNext() returnerer false vil den utløse NoSuchElementException.
  • void remove() - fjerner det siste elementet som ble returnert av next() fra den underliggende data-kilden, dersom den støtter dette. Denne metoden er frivillig å implementere, og dersom den ikke er støttet så skal den utløse UnsupportedOperationException.

...

Iterasjon med for-each-løkkeIterasjon med eksplisitt Iterator
Code Block
languagejava
// gå gjennom stringListe
for (String s : stringListe) {
	// gjør noe med s her
	...
}

 

 

Code Block
languagejava
// få en iterator fra stringListe 
Iterator<String> stringIterator = stringListe.iterator();
// bruk hasNext og next for å gå gjennom lista
while (stringIterator.hasNext()) {
	String s : stringIterator.next(); 
	// gjør noe med s her
	...
}

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

collectioniterable <|-upright- iterablecollection
listcollection <|-right- collectionlist
arraylistlist <|.down. arraylist
list
linkedlist <|.down. 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:

  • Iterator<type> iterator() - returnerer en Iterator<type> for å iterere over objektet.

Under følger et eksempel på Library-klassen fra eksempelet over, som implementerer Iterable<Book>:

...

languagejava
linkedlist

Som vi ser er også Iterable spesialisert til element-typen. Så dersom en har en List<String> så har en implisitt en Iterable<String>, som har en iterator()-metode som returnerer en Iterator<String>, som har en next()-metode som returnerer en String.

Siden Iterable er et vanlig grensesnitt, så kan våre egne klasser utvide den og utnytte den kompakte for-each-syntaksen. Anta f.eks. at en har en Library-klasse, som bruker en ArrayList til å holde Book-objekter. Kode for en slik klasse er vist under til venstre. Dersom denne klassen også implementerer Iterable<Book> så kan en bruke for-each-løkka for å gå gjennom Book-objektene i et Library-objekt. Koden og klassediagram for denne utvidete Library-klassen er vist i midten og for-each-løkka er vist til høyre.

...

Klasse som bruker ArrayListKlasse som også implementerer IterableKlassediagramfor-each-løkke
Code Block
languagejava
public class Library {

	private Collection<Book> books = new ArrayList<Book>();

	public void addBook(Book book) {
		books.add(book);
	}
	public void removeBook(Book book) {
		books.remove(book);
	}
}
Code Block
languagejava
public class Library implements Iterable<Book> {

	

...

... books-feltet og 

...

add- 

...

og 

...

remove-metodene 

...

her ...

	// fra Iterable<Book>
	public Iterator<Book> iterator() {
		return 

...

books.iterator();
	}
}

...

 

...

 

PlantUML Macro
interface "Iterable<Book>" as iterable {
	Iterator<Book> iterator()
}
class Library

iterable <|.. Library 
Code Block
// lag en Library-instans
Library library = new Library();
// legg til noen bøker
library.addBook(new Book(...));
library.addBook(new Book(...));

// gå gjennom bøkene
for (Book book : library
Code Block
languagejava
import java.util.Iterator;
 
public class Library implements Iterable<Book> {
	private ArrayList<Book> books;
	// Andre tilstander og metoder i klassen er ikke definert her
	
	public Iterator<Book> iterator() {
		// Returnerer ArrayList's iterator
		return books.iterator();
	}
}

Fordeler med Iterator / Iterable

Når et objekt implementerer Iterable<type> kan man bruke for-løkker av denne typen:

...

languagejava

...

) {
	// 

...

gjør 

...

noe 

...

med 

...

book her
	...
}
Ferdig
90