Gibt es eine gute Möglichkeit, dem Bestehenden einen neuen Wert hinzuzufügen Stream
? Ich kann mir nur so etwas vorstellen:
public <T> Stream<T> addToStream(Stream<T> stream, T elem ) {
List<T> result = stream.collect(Collectors.toList());
result.add(elem);
return result.stream();
}
Aber ich suche etwas Prägnanteres, das ich ohne Ausführlichkeit im Lambda-Ausdruck verwenden kann.
Eine andere Frage tauchte auf, als ich versuchte, das PECS- Prinzip umzusetzen :
public <T> Stream<? super T> addToStream(Stream<? super T> stream, T elem ) {
List<? super T> result = stream.collect(Collectors.toList()); //error
result.add(elem);
return result.stream();
}
Scheint, als würde Wildcard nicht funktionieren Stream.collect
und ich frage mich warum. Danke im Voraus.
List
voncollect(Collectors.toList())
Support zurückgegebenenadd
Daten verwendet werden.Collectors.toCollection
Stattdessen können Sie den Listentyp auswählen, den Sie erhalten.Antworten:
Die Frage widerlegt eine falsche Annahme: Streams enthalten tatsächlich ihre Daten. Sie nicht; Streams sind keine Datenstrukturen, sondern ein Mittel zum Spezifizieren von Massenoperationen in einer Vielzahl von Datenquellen.
Es gibt Kombinatoren zum Kombinieren von zwei Streams zu einem, z. B.
Stream.concat
Fabriken zum Erstellen von Streams aus einer Reihe bekannter Elemente (Stream.of
) oder aus Sammlungen (Collection.stream
). Sie können diese also kombinieren, wenn Sie einen neuen Stream erstellen möchten, der die Verkettung des vorhandenen Streams darstellt, sowie einen neuen Stream, der die neuen Elemente beschreibt.Das Problem in Ihrem PECS-Beispiel besteht darin, dass Sie drei Vorkommen
? super T
haben und davon ausgehen, dass sie denselben Typ beschreiben, dies jedoch nicht. Jedes Auftreten eines Platzhalters entspricht einer eindeutigen Erfassung, die nicht Ihren Wünschen entspricht. Sie müssen dieser Typvariablen einen Namen geben, damit der Compiler weiß, dass der Typ der Liste und der Typ des Eingabestreams identisch sind. (Materialisieren Sie auch keine Sammlung; das ist teuer und möglicherweise nicht terminierbar, wenn der Stream nicht endlich ist. Verwenden Sie einfach concat.) Die Antwort lautet also: Sie haben gerade die Generika falsch verstanden. Hier ist eine Möglichkeit, dies zu tun:public<T> Stream<T> appendToStream(Stream<? extends T> stream, T element) { return Stream.concat(stream, Stream.of(element)); }
Sie haben sich mit PECS verwechselt, weil Sie darüber nachgedacht haben, in den Stream einzufügen, obwohl Sie tatsächlich davon konsumieren.
quelle
concat
Methode kann verwenden, aber nicht zu viel, von Javadoc: Seien Sie vorsichtig, wenn Sie Streams aus wiederholter Verkettung erstellen. Der Zugriff auf ein Element eines stark verketteten Streams kann zu tiefen Aufrufketten oder sogar zu StackOverflowException führen.Wie wäre es mit
return Stream.concat(stream, Stream.of(elem));
Dies setzt voraus, dass der ursprüngliche Stream endlich ist. Wenn dies nicht der Fall ist, können Sie sie in umgekehrter Reihenfolge zusammenfassen.
quelle
Die StreamEx Bibliothek entspricht
#prepend()
und#append()
Methoden. Hier ist ein Beispiel, wie sie verwendet werden können:StreamEx.of("second").prepend("first").append("third").forEach(System.out::println);
Eine Ausgabe lautet wie folgt:
quelle
Am besten verwenden Sie eine flatMap wie folgt:
public <T> Stream<T> appendToStream(Stream<T> stream, T element) { return stream.flatMap(e -> Stream.of(e, element)); }
Dies funktioniert auf dem ursprünglichen Stream, so dass es sich nur um eine weitere Zwischenoperation auf dem Stream handeln kann, z.
quelle