Gibt es eine Java 8-Stream-Operation, die a (möglicherweise unendlich) begrenzt, Stream
bis das erste Element nicht mehr mit einem Prädikat übereinstimmt?
In Java 9 können wir takeWhile
wie im folgenden Beispiel alle Zahlen unter 10 drucken.
IntStream
.iterate(1, n -> n + 1)
.takeWhile(n -> n < 10)
.forEach(System.out::println);
Da es in Java 8 keine solche Operation gibt, wie kann sie allgemein am besten implementiert werden?
java
java-8
java-stream
MForster
quelle
quelle
IntStream.iterate(1, n->n<10, n->n+1).forEach(System.out::print);
Antworten:
Eine solche Operation sein sollte möglich mit einem Java - 8
Stream
, aber es kann nicht notwendigerweise effizient durchgeführt werden - zum Beispiel, kann man nicht unbedingt parallelisieren eine solche Operation, wie Sie auf Elemente, um zu suchen.Die API bietet keine einfache Möglichkeit, dies zu tun, aber die wahrscheinlich einfachste Möglichkeit besteht darin
Stream.iterator()
, dieIterator
Implementierung für eine "Take-while" -Implementierung zu verpacken und dann zu aSpliterator
und dann zu a zurückzukehrenStream
. Oder - vielleicht - wickeln Sie das einSpliterator
, obwohl es in dieser Implementierung nicht mehr wirklich aufgeteilt werden kann.Hier ist eine ungetestete Implementierung von
takeWhile
aSpliterator
:quelle
Operationen
takeWhile
unddropWhile
wurden zu JDK 9 hinzugefügt. Ihr Beispielcodeverhält sich beim Kompilieren und Ausführen unter JDK 9 genau so, wie Sie es erwarten.
JDK 9 wurde veröffentlicht. Es kann hier heruntergeladen werden: http://jdk.java.net/9/
quelle
takeWhile
/dropWhile
: download.java.net/jdk9/docs/api/java/util/stream/Stream.htmltakeWhile
unddropWhile
nichtlimitWhile
undskipWhile
, um die Konsistenz mit der vorhandenen API zu gewährleisten?takeWhile
unddropWhile
sind ziemlich weit verbreitet und kommen in Scala, Python, Groovy, Ruby, Haskell und Clojure vor. Die Asymmetrie mitskip
undlimit
ist unglücklich. Vielleichtskip
undlimit
sollte genannt wordendrop
undtake
, aber die sind nicht so intuitiv , wenn Sie mit Haskell bereits vertraut sind.dropXXX
undtakeXXX
sind populärere Begriffe, aber ich kann persönlich mit den SQL-ähnlichenlimitXXX
und lebenskipXXX
. Ich finde diese neue Asymmetrie viel verwirrender als die individuelle Wahl der Begriffe ... :) (übrigens: Scala hat auchdrop(int)
undtake(int)
)allMatch()
ist eine Kurzschlussfunktion, mit der Sie die Verarbeitung stoppen können. Der Hauptnachteil ist, dass Sie Ihren Test zweimal durchführen müssen: einmal, um zu sehen, ob Sie ihn verarbeiten sollten, und erneut, um zu sehen, ob Sie weitermachen sollen.quelle
Stream.allMatch()
es sich um einen Kurzschluss handelt . Dies wird also auch bei einem unendlichen Stream wie abgeschlossen seinIntStream.iterate()
. Rückblickend ist dies natürlich eine sinnvolle Optimierung.peek
. Wenn ich nächsten Monat darauf stoßen würde, würde ich mir eine Minute Zeit nehmen, um mich zu fragen, warum der Programmierer vor mir überprüft hat, oballMatch
und dann die Antwort ignoriert hat.Als Folge der Antwort von @StuartMarks . Meine StreamEx- Bibliothek verfügt über den
takeWhile
Vorgang, der mit der aktuellen JDK-9-Implementierung kompatibel ist. Wenn es unter JDK-9 ausgeführt wird, wird es nur an die JDK-Implementierung delegiert (überMethodHandle.invokeExact
die es sehr schnell geht). Bei Ausführung unter JDK-8 wird die Implementierung "Polyfill" verwendet. Mit meiner Bibliothek kann das Problem also folgendermaßen gelöst werden:quelle
takeWhile
ist eine der Funktionen der Protonpack-Bibliothek .quelle
Update: Java 9 enthält
Stream
jetzt eine takeWhile- Methode.Keine Notwendigkeit für Hacks oder andere Lösungen. Benutze das einfach!
Ich bin sicher, dass dies erheblich verbessert werden kann: (Jemand könnte es vielleicht threadsicher machen)
Ein Hack sicher ... Nicht elegant - aber es funktioniert ~: D.
quelle
Sie können java8 + rxjava verwenden .
quelle
Tatsächlich gibt es in Java 8 zwei Möglichkeiten, dies ohne zusätzliche Bibliotheken oder mit Java 9 zu tun.
Wenn Sie Zahlen von 2 bis 20 auf der Konsole drucken möchten, können Sie dies tun:
oder
Die Ausgabe erfolgt in beiden Fällen:
Noch hat niemand anyMatch erwähnt . Dies ist der Grund für diesen Beitrag.
quelle
Dies ist die aus JDK 9 kopierte Quelle java.util.stream.Stream.takeWhile (Predicate). Ein kleiner Unterschied, um mit JDK 8 zu arbeiten.
quelle
Hier ist eine Version von Ints - wie in der Frage gestellt.
Verwendung:
Hier ist der Code für StreamUtil:
quelle
Gehen Sie zur Bibliothek AbacusUtil . Es bietet genau die gewünschte API und mehr:
Erklärung: Ich bin der Entwickler von AbacusUtil.
quelle
Sie können einen Stream nur durch einen Kurzschluss des Terminals abbrechen, wodurch einige Stream-Werte unabhängig von ihrem Wert unverarbeitet bleiben. Wenn Sie jedoch nur Operationen an einem Stream vermeiden möchten, können Sie dem Stream eine Transformation und einen Filter hinzufügen:
Das wandelt den Strom von Dingen in Nullen um, wenn die Dinge eine Bedingung erfüllen, und filtert dann Nullen heraus. Wenn Sie bereit sind, sich Nebenwirkungen hinzugeben, können Sie den Bedingungswert auf true setzen, sobald etwas auftritt, sodass alle nachfolgenden Dinge unabhängig von ihrem Wert herausgefiltert werden. Aber selbst wenn nicht, können Sie viel (wenn nicht sogar die gesamte) Verarbeitung sparen, indem Sie Werte aus dem Stream herausfiltern, die Sie nicht verarbeiten möchten.
quelle
Sogar ich hatte eine ähnliche Anforderung: Rufen Sie den Webdienst auf. Wenn dies fehlschlägt, wiederholen Sie ihn dreimal. Wenn dies auch nach diesen vielen Versuchen fehlschlägt, senden Sie eine E-Mail-Benachrichtigung. Nachdem ich viel gegoogelt hatte,
anyMatch()
kam ich als Retter. Mein Beispielcode wie folgt. Wenn im folgenden Beispiel die webServiceCall- Methode in der ersten Iteration selbst true zurückgibt, iteriert der Stream nicht weiter, wie wir es aufgerufen habenanyMatch()
. Ich glaube, das ist es, wonach Sie suchen.quelle
Wenn Sie genau wissen, wie viele Wiederholungen durchgeführt werden, können Sie dies tun
quelle
Anstelle von Peak können Sie mapToObj verwenden, um das endgültige Objekt oder die endgültige Nachricht zurückzugeben
quelle
Wenn Sie ein anderes Problem haben, ist möglicherweise eine andere Lösung erforderlich, aber für Ihr aktuelles Problem würde ich einfach gehen mit:
quelle
Könnte ein bisschen vom Thema abweichen, aber das ist es, wofür wir es haben
List<T>
und nichtStream<T>
.Zuerst benötigen Sie eine
take
util-Methode. Diese Methode verwendet ersten
Elemente:es funktioniert einfach so
scala.List.take
Jetzt wird es ziemlich einfach sein, eine
takeWhile
Methode zu schreiben , die auf basierttake
es funktioniert so:
Diese Implementierung iteriert die Liste einige Male teilweise, fügt jedoch keine zusätzlichen
O(n^2)
Operationen hinzu. Hoffe das ist akzeptabel.quelle
Ich habe eine andere schnelle Lösung, indem ich dies implementiere (was in der Tat ziemlich unrein ist, aber Sie bekommen die Idee):
quelle
current
nie.equals(e)
, erhalten Sie eine Endlosschleife. Beides auch wenn Sie sich später bewerben zB.limit(1)
. Das ist weitaus schlimmer als "unrein" .Hier ist mein Versuch, nur die Java Stream-Bibliothek zu verwenden.
quelle
filter
Prädikat soll staatenlos sein.System.out.println
ist eine Nebenwirkung.