Ich benutze den Stream-Spliterator direkt für die Low-Level-Operationen in der Bibliothek, die ich schreibe. Vor kurzem habe ich sehr seltsames Verhalten entdeckt, wenn ich den Stream spliterator nehme und tryAdvance/trySplit
Aufrufe interleave. Hier ist ein einfacher Code, der das Problem demonstriert:Seltsames Verhalten von Stream.spliterator für parallele Ströme
import java.util.Arrays;
import java.util.Spliterator;
public class SpliteratorBug {
public static void main(String[] args) {
Integer[][] input = { { 1 }, { 2, 3 }, { 4, 5, 6 }, { 7, 8 }, { 9 } };
Spliterator<Integer> spliterator = Arrays.stream(input).parallel()
.flatMap(Arrays::stream).spliterator();
spliterator.trySplit();
spliterator.tryAdvance(s -> {});
spliterator.trySplit();
spliterator.forEachRemaining(System.out::println);
}
}
Der Ausgang ist
5
6
9
Wie Sie sehen können, nach dem Flat-Mapping I sollte den geordneten Strom von aufeinanderfolgenden Zahlen 1
-9
zu bekommen. Ich spalte den Spliterator einmal, also sollte er an einen Zwischenplatz springen. Als nächstes verzehre ich ein Element daraus und spalte es noch einmal. Danach drucke ich alle restlichen Elemente. Ich erwarte, dass ich mehrere aufeinanderfolgende Elemente aus dem Stream Tail haben werde (wahrscheinlich null Elemente, es wäre auch in Ordnung). Was ich jedoch bekomme, ist 5
und 6
, dann plötzlich auf 9
springen.
Ich weiß, dass derzeit in JDK-Spliteratoren nicht auf diese Weise verwendet werden: Sie teilen immer vor dem Durchlauf. Jedoch verbietet es der Beamte documentation nicht ausdrücklich, die trySplit
nach tryAdvance
anzurufen.
Das Problem wurde nie beobachtet, wenn ich Spliterator direkt aus Sammlung, Array, generierte Quelle usw. verwendet. Es wird nur beobachtet, wenn der Spliterator aus dem parallelen Strom, der das Zwischenprodukt flatMap
hatte, erstellt wurde.
Die Frage ist also: Habe ich den Fehler gefunden oder ist es explizit verboten, den Spliterator auf diese Weise zu verwenden?