Natürlich ist es wichtig, wie wenn Sie m2.addAll(m1)
anstelle von m1.addAll(m2)
verwenden, ändert es nicht nur die Reihenfolge der Elemente, sondern bricht den Vorgang vollständig. Da ein BiConsumer
kein Ergebnis zurückgibt, haben Sie keine Kontrolle darüber, welches Objekt der Aufrufer als Ergebnis verwendet, und da der Aufrufer das erste verwendet, führt das Ändern des zweiten statt dessen zu Datenverlust.
Es gibt einen Hinweis, wenn Sie an der Akkumulator aussehen Funktion, die den Typ hat BiConsumer<R,? super T>
, mit anderen Worten, das Element des Typs nicht irgend etwas anderes tun kann, als zu speichern T
, als zweites Argument vorgesehen ist, in den Behälter des Typs R
, als erstes Argument zur Verfügung gestellt.
Wenn man sich die documentation of Collector
suchen, die eine BinaryOperator
als Kombinierer Funktion verwendet, ermöglicht somit die Kombinierer zu entscheiden, welches Argument (oder sogar ein ganz anderes Ergebnis Instanz) zurückkehren, finden Sie:
Die Assoziativitätsbeschränkung besagt, dass das Teilen der Berechnung ein äquivalentes Ergebnis ergeben muss.Das heißt, für alle Eingabeelemente t1
und t2
, die Ergebnisse r1
und r2
bei der Berechnung unten muss gleichwertig sein:
A a1 = supplier.get();
accumulator.accept(a1, t1);
accumulator.accept(a1, t2);
R r1 = finisher.apply(a1); // result without splitting
A a2 = supplier.get();
accumulator.accept(a2, t1);
A a3 = supplier.get();
accumulator.accept(a3, t2);
R r2 = finisher.apply(combiner.apply(a2, a3)); // result with splitting
Wenn wir also davon ausgehen, dass der Akkumulator in Begegnung angelegt wird, die Kombinator muss das erste und das zweite Argument in der Reihenfolge von links nach rechts kombinieren, um ein äquivalentes Ergebnis zu erhalten.
nun die drei argument Version von Stream.collect
hat eine etwas andere Signatur, einen BiConsumer
als Kombinierer mitexactly for supporting method references like ArrayList::addAll
. Unter der Annahme der Konsistenz bei allen diesen Operationen und unter Berücksichtigung des Zwecks dieser Signaturänderung können wir sicher annehmen, dass es das erste Argument sein muss, das der Container zu modifizieren ist.
Aber es scheint, dass dies eine späte Änderung ist und die Dokumentation nicht entsprechend angepasst wurde. Wenn Sie sich den Abschnitt Mutable reduction der Paketdokumentation ansehen, werden Sie feststellen, dass er so angepasst wurde, dass er die tatsächlichen Stream.collect
Signatur- und Verwendungsbeispiele zeigt, aber exakt die gleiche Definition bezüglich der Assoziativitätsbeschränkung wie oben gezeigt wiederholt, trotz der Tatsache finisher.apply(combiner.apply(a2, a3))
nicht funktioniert, wenn combiner
ein BiConsumer
ist ...
Die Dokumentation Problem wurde als JDK-8164691 und adressiert in Java berichtet 9. The new documentation sagt:
Kombinierer - ein assoziatives, nicht-int Englisch: www.weisang.info/index.php?id=143&t...h=cfd8d3eaa9 Erbringen, zustandslose Funktion, die zwei Teilergebnisbehälter akzeptiert und zusammenführt, die mit der Akkumulatorfunktion kompatibel sein müssen Die Combiner-Funktion muss die Elemente aus dem zweiten Ergebniscontainer in den ersten Ergebniscontainer falten.
Sie haben Recht, das Javadoc ist nicht sehr klar geschrieben - verwirrend, sagt es, dass Combiner assoziativ sein muss !. Es ist wahrscheinlich ein Rest von einer früheren Version, die einen 'BinaryOperator' anstelle eines' BiConsumer' verwendet hat. Aber aus den gegebenen Beispielen ist es klar, dass der Kombinierer sich in seinem ersten Argument ansammeln muss. – Misha