Stream
erbt eine iterator () -Methode, um eine zu erzeugen Iterator
.
Aber ich brauche Iterable
eher eine als eine Iterator
.
Beispiel: Diese Zeichenfolge lautet:
String input = "this\n" +
"that\n" +
"the_other";
… Ich muss diese Teile der Zeichenfolge als Iterable
an eine bestimmte Bibliothek übergeben. Aufruf input.lines()
ergibt a Stream
. Ich wäre also bereit, wenn ich das Stream
zu einem Iterable
seiner Elemente machen könnte.
java
java-stream
iterable
Basil Bourque
quelle
quelle
Antworten:
Wie unter Warum implementiert Stream <T> Iterable <T> nicht? , a
Iterable
trägt die Erwartung,Iterator
mehr als einmal liefern zu können , was einStream
nicht erfüllen kann. Während Sie also einIterable
OutStream
für Ad-hoc-Zwecke erstellen können , müssen Sie vorsichtig sein, ob Versuche bestehen, es mehrmals zu wiederholen.Da Sie gesagt haben: " Ich muss diese Teile der Zeichenfolge als
Iterable
an eine bestimmte Bibliothek übergeben ", gibt es keine allgemeine Lösung, da der Code, derIterable
das verwendet, außerhalb Ihrer Kontrolle liegt.Wenn Sie jedoch derjenige sind, der den Stream erstellt, können Sie einen gültigen
Iterable
Stream erstellen, der die Stream-Konstruktion jedes Mal wiederholt, wenn eineIterator
angefordert wird:Dies erfüllt die Erwartung, eine beliebige Anzahl von Iterationen zu unterstützen, während nicht mehr Ressourcen als ein einzelner Stream verbraucht werden, wenn nur einmal durchlaufen wird.
quelle
Iterable<String> lines = "this\nthat\nthe_other".lines()::iterator;
dies zwar einer der seltenen Fälle ist, in denen eine Methodenreferenz nicht mit einem Lambda identisch ist und tatsächlich unerwünschte Auswirkungen hätte.expression::name
sind niemals mit Lambda-Ausdrücken identisch, auch nicht fürSystem.out::println
. Aber hier haben wir einen der Fälle, in denen es darauf ankommtStream<String> lines = str.lines();
Sie dann dasIterable<String> iter = lines::iterator
Versus erstellen()->lines.iterator()
.stream::iterator
und gab() -> stream.iterator()
. In meiner Antwort heißt es genau: Es gibt keine allgemeine Lösung für die Konvertierung eines vorhandenen Streams in eine gültige Iterable, die mehrere Iterationen zulässt. Das Wiederholen der Stream-Konstruktion jedes Mal, wenn ein Iterator angefordert wird, dh hier bedeutet dies, dasslines()
jedes Mal aufgerufen wird, macht den Unterschied aus.expression::name
bedeutet " einmal auswertenexpression
und das Ergebnis erfassen ", während() -> expression.name(…)
" jedes Mal auswerten,expression
wenn der Funktionskörper ausgewertet wird " bedeutet. Die Unterschiede sind winzig, wenn "expression
" nur eine lokale Variable ist, aber selbst dann ist es anders, dh esstream::iterator
wird sich anders verhalten als() -> stream.iterator()
wenn esstream
istnull
. Meine Aussage giltexpression::name
also immer noch, unterscheidet sich immer von einem Lambda-Ausdruck, die Frage ist, wie wichtig es für meinen speziellen Anwendungsfall ist.tl; dr
Einfach besetzen , keine Konvertierung nötig.
Besetzung
Stream < String >
zuIterable < String >
.Einzelheiten
VORSICHT Siehe Antwort von Holger, in der die Gefahren der Verwendung eines Stream-Backed erläutert werden
Iterable
.Ja, du kannst
Iterable
aus einem machenStream
.Die Lösung ist einfach, aber nicht offensichtlich. Siehe diesen Beitrag in den Lambda-FAQ von Maurice Naftalin .
Die
iterator()
Methode zur Rückgabe von aBaseStream
(Oberklasse vonStream
)Iterator
stimmt zufällig mit demselben Namen deriterator()
Methode überein, die a zurückgibt,Iterator
wie von derIterable
Schnittstelle gefordert . Die Methodensignaturen stimmen überein. Also haben wir eigentlich die werfen können ,Stream
um einIterable
, benötigt keine Konvertierung.Machen Sie Ihre Eingabe.
Wirf das
Stream<String>
aufIterable<String>
.Testen Sie die Ergebnisse.
Sehen Sie diesen Code live auf IdeOne.com .
CAVEAT Achten Sie auf das Risiko von Stream-Backed
Iterable
. Erklärt in der richtigen Antwort von Holger .quelle
Stream<String>
weilstream::iterator
es nicht vom Typ istStream<String>
.Iterable
über eine Methodenreferenz. Das(Iterable<String>)
teilt dem Compiler nur mit, welche funktionale Schnittstelle das Ziel ist.(Iterable<String>)
etwas anderes als eine Besetzung ist, aber ich verstehe die Situation sicherlich nicht, da Ihre Kommentare mich dazu veranlassten, eine zusätzliche Gruppe von Parens zu verwenden,( (Iterable<String>) stream )
die dazu führen, dass der Code fehlschlägt - was beweist, dass mein Verständnis fehlerhaft ist. Bitte bearbeiten Sie meine Antwort, um dies zu klären, oder veröffentlichen Sie Ihre eigene Antwort mit einer besseren Erklärung.(Iterable<String>)()->stream.iterator()
oder noch expliziternew Iterable<String>(){ public Iterator<String> iterator(){ return stream.iterator();}
. Sie übertragen also keinen Stream auf Iterable, was fehlschlagen würde.