Beim Blick in die Umsetzung (ReferencePipeline.java
) wir die Methode [link]
@Override
final void forEachWithCancel(Spliterator<P_OUT> spliterator, Sink<P_OUT> sink) {
do { } while (!sink.cancellationRequested() && spliterator.tryAdvance(sink));
}
die für findFirst
Betrieb aufrufen wird, zu sehen. Das Besondere ist die sink.cancellationRequested()
, mit der die Schleife bei der ersten Übereinstimmung beendet werden kann. Vergleichen Sie auf [link]
@Override
public final <R> Stream<R> flatMap(Function<? super P_OUT, ? extends Stream<? extends R>> mapper) {
Objects.requireNonNull(mapper);
// We can do better than this, by polling cancellationRequested when stream is infinite
return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
@Override
Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
return new Sink.ChainedReference<P_OUT, R>(sink) {
@Override
public void begin(long size) {
downstream.begin(-1);
}
@Override
public void accept(P_OUT u) {
try (Stream<? extends R> result = mapper.apply(u)) {
// We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
if (result != null)
result.sequential().forEach(downstream);
}
}
};
}
};
}
Verfahren für ein Stück voran landet forEach
auf dem Teilstrom Aufruf ohne jede Möglichkeit für eine frühere Beendigung und den Kommentar am Anfang der flatMap
Methode teilt auch diese abwesende Funktion.
Da es sich um mehr als nur eine Optimierung etwas wie impliziert es, dass der Code einfach bricht, wenn der Teilstrom unendlich ist, hoffe ich, dass die Entwickler bald beweisen, dass sie „kann als dies besser tun“ ...
Um die Implikationen zu veranschaulichen, während Stream.iterate(0, i->i+1).findFirst()
wie erwartet funktioniert, wird Stream.of("").flatMap(x->Stream.iterate(0, i->i+1)).findFirst()
in einer Endlosschleife enden.
...
Zwischenoperationen einen neuen Stream zurück:
die Spezifikation betrifft, können die meisten davon in der
chapter “Stream operations and pipelines” of the package specification finden. Sie sind immer faul;
...
... Laziness ermöglicht auch die Vermeidung alle Daten, die Prüfung, wenn es nicht notwendig ist; Für Operationen wie "finde die erste Zeichenfolge, die länger als 1000 Zeichen ist" ist es nur notwendig, gerade genug Zeichenfolgen zu untersuchen, um eine zu finden, die die gewünschten Eigenschaften aufweist, ohne alle Zeichenfolgen zu untersuchen, die von der Quelle verfügbar sind. (Dieses Verhalten wird umso wichtiger, wenn der Eingangsstrom unendlich ist und nicht nur groß.)
...
Des Weiteren werden einige Operationen als Kurzschließen Operationen. Eine Zwischenoperation ist kurzgeschlossen, wenn sie, wenn sie mit einer unendlichen Eingabe dargestellt wird, als Ergebnis einen endlichen Strom erzeugen kann. Eine terminale Operation ist kurzgeschlossen, wenn sie, wenn sie mit einer unendlichen Eingabe dargestellt wird, in einer endlichen Zeit enden kann. Eine Kurzschlußoperation in der Pipeline ist eine notwendige, aber nicht ausreichende Bedingung für die Verarbeitung eines unendlichen Stroms, der normalerweise in endlicher Zeit endet.
Es ist klar, dass ein Kurzschlussbetrieb keine endliche Zeitbeendigung, z. Wenn ein Filter nicht mit einem Element übereinstimmt, kann die Verarbeitung nicht abgeschlossen werden, aber eine Implementierung, die keine Beendigung in endlicher Zeit durch einfaches Ignorieren der Kurzschlußart einer Operation unterstützt, liegt weit außerhalb der Spezifikation.
Ich verstehe wirklich nicht Ihr Problem. Warum sollte es sich anders verhalten? –
@PhilippSander: Denn wenn es sich träge verhält - wie im ersten Fall - würde es den Filter nur einmal auswerten. –
ah .... es klickte, wenn ich Markos antworte –