Ich habe eine Implementierung von java.util.Iterator
, die erfordert, dass der Aufruf von next()
immer mit einem Aufruf von hasNext()
fortgesetzt wird. (Dies liegt daran, dass die Ergebnisse asynchron in einer Umgebung mit mehreren Threads zurückgegeben werden und es nie klar ist, wie viele weitere Ergebnisse es gibt).
Wäre es "richtig", dies im JavaDoc richtig zu dokumentieren und dann ein RuntimeException
zu werfen, wenn dies verletzt wurde. Oder dehnt sich die Iterator-Schnittstelle etwas zu weit aus?
Alle Gedanken geschätzt?
Ich vermisse etwas hier, aber warum nicht hasNext()
intern in Ihrer Implementierung aufrufen?
Ich kann mir vorstellen, dass Sie so etwas tun:
%Vor% Das klingt OK für mich. Ich kann mir keine Situation vorstellen, in der Sie next
ohne hasNext
verwenden möchten - es wäre ein Rezept für Ausnahmen.
BEARBEITEN:
Das Dokument für hasNext()
sagt :
Gibt true zurück, wenn die Iteration mehr Elemente enthält. (Mit anderen Worten, gibt true zurück, wenn next ein Element zurückgibt, anstatt eine Ausnahme auszulösen.)
Für mich verletzt die Implementierung nicht den Vertrag. Allerdings würde ich (wie Fabian Steeg impliziert) ( ) weiterhin next()
als implementieren:
Ich meine, was kostet Sie das wirklich?
Sie müssen ein NoSuchElementException
überprüfen und ausgeben, wie in der API-Vertrag . Entweder wird das Testen auf !hasNext()
oder next == null
diese Kriterien erfüllen, glaube ich, aber ich würde das erste bevorzugen.
Wenn jemand NoSuchElementException
anstatt hasNext()
abruft, haben Sie wahrscheinlich größere Probleme.
Wenn Ihre Aufrufe hasNext()
und next()
nicht in einer synchronisierten Block / Methode sind, ist es nicht garantiert, dass Sie Elemente haben, selbst wenn Sie hasNext()
vor next()
aufrufen.
Der Vertrag der Schnittstelle Iterator
besagt, dass NoSuchElementException
ausgelöst werden sollte, wenn keine weiteren Elemente vorhanden sind. Fahren Sie mit der Methode next()
fort, bis eine solche Ausnahme auftritt.
Sehen Sie sich dazu die java.util.concurrent
an. Paket - es hat gleichzeitige Sammlungen, deren Iteratoren Ihnen helfen können - dh Sie können diese Sammlungen und Iteratoren verwenden anstatt Ihre eigenen zu implementieren.
Ich würde eher eine Ausnahme von next()
werfen, wenn es keine Elemente mehr gibt. In einer Multithread-Umgebung ist hasNext()
sowieso ziemlich nutzlos.
Sie können die Schnittstelle Iterator
selbst implementieren (falls Sie eine Schnittstelle mit einer anderen API benötigen) und Ihre Kunden auffordern, Ihre eigene strengere Schnittstelle zu implementieren.
Ich habe eine solche Klasse in meiner funktionalen Programmierbibliothek erstellt, um einfach ein Iterator
um ein ResultSet
in einem Projekt bei der Arbeit zu implementieren.
Meine Klasse EasierIterator implementiert die Iterator-Schnittstelle bei Bedarf dass der Client eine einfachere Schnittstelle basierend auf moveNext()
/ getCurrent()
implementiert. Es macht tatsächlich das Zwischenspeichern des aktuellen Artikels für Sie.
Sie könnten etwas Ähnliches wie das Folgende tun, wobei Sie den zugrunde liegenden Datenabruf an eine private Methode delegieren und hasNext()
und next()
implementieren, um unterschiedlich auf die Abwesenheit von Daten zu reagieren. Dies hat den Vorteil, dass Sie next()
immer wieder aufrufen können, ohne zuerst hasNext()
aufzurufen, und daher nicht gegen den Vertrag von Iterator verstößt.
BEARBEITEN: In dieser Antwort habe ich versucht zu argumentieren, dass es erlaubt ist, worum die Frage geht. Aber ich habe einen Satz in der Iterator.hasNext
-Dokumentation übersehen, der meine ganze Argumentation entwertet:
Mit anderen Worten, gibt true zurück, wenn
next()
ein Element zurückgibt und keine Ausnahme auslöst.
Dies deutet darauf hin, dass next
wiederholt aufgerufen wird, bis hasNext
wahr zurückgibt und als nächstes aufruft, bis ein NoSuchElementException
die gleiche Sequenz von Elementen zurückgibt.
So scheint es, dass das, wonach die Frage fragt, nicht erlaubt ist.
Dies ist ein Versuch, eine Anwaltsart zu spezifizieren. Aus Gründen der Klarheit werde ich die Frage in einer kompakten Form wiederholen:
Ist es erlaubt durch die
Iterable
Spezifikation eineNoSuchElementException
zu werfen, wennIterator.next
aufgerufen wird ohne einen vorhergehenden Aufruf vonIterator.hasNext
, auch wenn ein Element zurückgegeben worden wäre, wennIterator.hasNext
zuerst aufgerufen wurde?
Die Dokumentation zu Iterator.hasNext
lautet :
Gibt true zurück, wenn die Iteration mehr Elemente enthält.
Und für Iterator.next
:
Wirf:
NoSuchElementException
- wenn die Iteration keine Elemente mehr enthält
Anscheinend ist es erlaubt, NoSuchElementException
zu werfen, wenn "die Iteration keine Elemente mehr hat", aber vorher nicht. Das sollte übereinstimmen, wenn hasNext
false zurückgibt.
Daraus ergibt sich die Frage: Was genau bedeutet die Dokumentation mit "der Iteration" und "Elementen"? Die Iterator
-Dokumentation gibt keine Antwort darauf, was den Implementierern etwas Spielraum lässt.
Aus meiner Sicht gibt es zwei mögliche Interpretationen:
Aus der Perspektive der Iteratorschnittstelle selbst ist das einzige existierende Konzept von "Iteration" "solange hasNext
wahr zurückgibt". Das heißt, wenn der Client next
vor hasNext
aufruft, wissen sie nicht, ob mehr Elemente vorhanden sind, undefiniert.
Es ist daher durch die Spezifikation für den Iterator-Implementierer erlaubt zu entscheiden, dass die Iteration beendet ist. Also ist die Antwort auf die Frage ja.
Aber die Dokumentation zu Iterable.iterator
Erwähnen Sie auch "Elemente":
Gibt einen Iterator über Elemente vom Typ
T
zurück.
Was bedeutet "Elemente" hier? Bedeutet es "alle Elemente in der Sammlung, die Iterable
implementieren? Nein, das sagt es nicht, und nicht alle iterierbaren Elemente haben eine feste Menge von Elementen.
Was "Elemente" für bestimmte iterierbare Elemente bedeuten, bleibt dem Implementierer überlassen. Eine gültige Definition von "Elementen" für einen Iterator könnte sein: " alle Elemente in der Sammlung ODER alle Elemente, bevor der Client entscheidet, next
vor hasNext
" aufzurufen.
Dieser Fall führt also auch zu der Schlussfolgerung, dass die Antwort auf die Frage ja lautet. (Aber bitte beachten Sie den Hinweis am Ende!)
Die Dokumentation ist nicht wirklich klar, aber es scheint, als ob die Antwort auf die Frage lautet: Ja, das ist erlaubt.
Falls ein Iterator das tut, was die Frage zu diesem Verhalten stellt, sollte dies natürlich dokumentiert werden. Aber andere Iterables sollten auch dokumentieren, welche Elemente ihre Iteratoren sind.
Beispiel: ArrayList.iterator
Die Dokumentation gibt eindeutig an, welche Elemente den Iterator durchlaufen:
Gibt einen Iterator über die Elemente in dieser Liste in der richtigen Reihenfolge zurück.
Schlussbemerkung: Ja, ich bin verrückt, so viel Zeit damit zu verbringen.
Tags und Links java concurrency iterator