Arrays mit Iteratoren durchlaufen
Implementierung eines ArrayIterator.
Die Konzepte Array und Container-Objekte passen oft nicht genau zusammen, da zwischen ihnen ein Bruch in der Programmierung liegt. Beide werden unterschiedlich angesprochen: ein Container häufig mittels Iteratoren, ein Array direkt über einen ganzzahligen Index. Wenn es nicht auf Geschwindigkeit ankommt, sollten wir als Container besser eine Datenstruktur verwenden und kein "rohes" Array. Bei einem Array müssen wir uns immer selbst um Strategien zum Durchlaufen der Array-Elemente kümmern, bei Datenstrukturen haben wir das Konzept der Enumeratoren und Iteratoren. Gut ist es, ein Array nachträglich mit derselben Abstraktion auszustatten wie eine Datenstruktur, also mit einem Iterator. Folgende Implementierung soll uns dabei helfen, von den Vorteilen eines Iterators zu profitieren. Dadurch kann zum Beispiel ein Array leichter gegen eine mächtigere Datenstruktur ausgetauscht werden. Wir müssen dazu nur für drei Methoden Programmcode bereitstellen: hasNext(), next() und remove(). Für Letztere wollen wir keine Implementierung bieten und eine UnsupportedOperationException auslösen, da beim Löschen eigentlich auch das Feld kleiner werden muss.
Damit sieht die Klasse ArrayIterator wie folgt aus:
public class ArrayIterator implements Iterator
{
private Object array[];
private int pos = 0;
public ArrayIterator( Object anArray[] )
{
array = anArray;
}
public boolean hasNext()
{
return pos < array.length;
}
public Object next() throws NoSuchElementException
{
if ( hasNext() )
return array[pos++];
else
throw new NoSuchElementException();
}
public void remove()
{
throw new UnsupportedOperationException();
}
}
Ein ArrayIterator wird über einen parametrisierten Konstruktor für ein bestimmtes Array-Objekt erzeugt. Die Funktion nextElement() löst eine NoSuchElementException aus, wenn das Ergebnis false von hasMoreElements() ignoriert wird. NoSuchElementException ist eine RuntimeException, sodass sie nicht ausdrücklich aufgefangen werden muss.
Das Array kann parallel im Hintergrund noch verändert werden. Da sich die Größe allerdings nicht mehr ändern kann, müssen wir die ersten beiden kritischen Zeilen in next() nicht synchronisieren. Praktisch bei dem ArrayIterator ist nun, dass er an alle Funktionen weitergegeben werden kann, die einen Iterator als Parameter erwarten und kein remove() verwenden. Sonst hätten wir eine andere Datenstruktur wählen müssen.
Folgendes Beispiel zeigt unseren neuen Iterator im Einsatz beim Aufzählen der Kommandozeilen-Argumente:
static public void main( String arg[] )
{
Iterator i = new ArrayIterator( arg );
while ( i.hasNext() )
System.out.println( "Eintrag: " + i.next() );
}