1.4-Software-Development-Principles

Iterable (en Iterator)

Inleiding

De meest eenvoudige manier om een lijst te representeren is via de Iterable interface. Deze interface maakt het mogelijk om te itereren over de verschillende elementen in de lijst. Een extra bonus is dat wanneer deze interface geimplementeerd is, je gebruikt kunt maken van een enhanced for-loop om door de elementen jouw eigen LinkedList gaan.

De Iterable interface ziet er als volgt uit*:

public interface Iterable<T> {
    Iterator<T> iterator();
}

*Eigenlijk zijn er nog twee methoden, maar dit is de enige die je moet implementeren. (Hebben we het al gehad over “default” implementaties? Voel je vrij om dit detail te negeren.)

De ene method van Iterable geeft een specifieke implementatie terug van Iterator. Deze definieert twee methoden:

public interface Iterator<T> {
    T next();
    boolean hasNext();
}

Je zou een gewone loop kunnen schrijven door gebruik te maken van die iterator:

for (Iterator<T> i=list.iterator(); i.hasNext(); ) {
    T current = i.next();    	
}

Maar het is natuurlijk veel logischer om gewoon dit te doen:

for (T current:list) {
	
}

Note: Om het helemaal duidelijk te maken:

Opdracht

Stap 1: Zorg dat jouw lijst de Iterable interface implementeerd.

Voeg de interface toe aan de klasse en begin met het schrijven van de iterable() methode. Je zult daar nog niet zo heel veel mee kunnen. Dus geef voorlopig gewoon null terug.

Stap 2: Definieer een interne klasse die de Iterator interface gebruikt.

Aan het eind van je klasse definitie, maar wel binnen de body van de klasse declareren we een nieuwe classe. Noem hem MyIterator als je wilt.

Note: We gaan er vanuit dat de referentie naar de root node gedeclareerd is als private. Maar omdat deze nieuwe interne klasse een integraal onderdeel is van de lijst klasse heeft hij toegang tot private velden.

Het doel van de Iterator is om over alle nodes van jouw lijst te lopen.

Samenvatting

Nu dat jouw eigen LinkedList klasse de Iterable interface implementeerd, kun je specifieke unittests schrijven. Ik vind de volgende methoden handig, voel je vrij om ze te “lenen”.

@Test
public void GivenMyOwnList_WhenIterating_AllValuesMatch() {
    // This is an example
    assertContent(myOwnList, "Item 1", "Item 2", "Item 3", "Item 4");	
}

public static <Q> void assertContent(Iterable<Q> iterable, Q... values) {
    assertNotNull(iterable);
    assertContent(iterable.iterator(), values);
    // Or use the built in:
    assertIterableEquals(iterable, values);
}

public static <Q> void assertContent(Iterator<Q> iterator, Q... values) {
    for (Q value:values) {
        assertTrue(iterator.hasNext());
        Q actual = iterator.next();
        assertEquals(value, actual);
    }
    assertFalse(iterator.hasNext());
}