Ich frage mich, warum die Iterable
Schnittstelle die stream()
und parallelStream()
Methoden nicht bereitstellt . Betrachten Sie die folgende Klasse:
public class Hand implements Iterable<Card> {
private final List<Card> list = new ArrayList<>();
private final int capacity;
//...
@Override
public Iterator<Card> iterator() {
return list.iterator();
}
}
Es ist eine Implementierung einer Hand, da Sie beim Spielen eines Sammelkartenspiels Karten auf der Hand haben können.
Im Wesentlichen umschließt es a List<Card>
, stellt eine maximale Kapazität sicher und bietet einige andere nützliche Funktionen. Es ist besser, es direkt als zu implementieren List<Card>
.
Aus Bequemlichkeitsgründen dachte ich, es wäre schön, es so zu implementieren Iterable<Card>
, dass Sie erweiterte for-Schleifen verwenden können, wenn Sie eine Schleife darüber erstellen möchten. (Meine Hand
Klasse bietet auch eine get(int index)
Methode, daher Iterable<Card>
ist die meiner Meinung nach gerechtfertigt.)
Die Iterable
Schnittstelle bietet Folgendes (ausgelassenes Javadoc):
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
Jetzt können Sie einen Stream erhalten mit:
Stream<Hand> stream = StreamSupport.stream(hand.spliterator(), false);
Also auf die eigentliche Frage:
- Warum gibt es
Iterable<T>
keine Standardmethoden, die implementiert werden,stream()
undparallelStream()
ich sehe nichts, was dies unmöglich oder unerwünscht machen würde?
Eine verwandte Frage, die ich gefunden habe, lautet jedoch: Warum implementiert Stream <T> Iterable <T> nicht?
Was seltsamerweise darauf hindeutet, es etwas anders herum zu machen.
quelle
break;
eine Iteration? (Ok,Stream.findFirst()
könnte eine Lösung sein, aber das könnte nicht alle Anforderungen erfüllen ...)Antworten:
Dies war keine Auslassung; Im Juni 2013 wurde die EG-Liste ausführlich erörtert.
Die endgültige Diskussion der Expertengruppe basiert auf diesem Thread .
Während es "offensichtlich" schien (anfangs sogar für die Expertengruppe),
stream()
was Sinn machteIterable
, wurde die Tatsache, dassIterable
es so allgemein war, zu einem Problem, weil die offensichtliche Unterschrift:war nicht immer das, was du wolltest. Bei einigen Dingen
Iterable<Integer>
würde beispielsweise die Stream-Methode lieber eine zurückgebenIntStream
. Aber diestream()
Methode so hoch in der Hierarchie zu platzieren, würde dies unmöglich machen. Stattdessen haben wir es wirklich einfach gemacht,Stream
aus einem zu machenIterable
, indem wir einespliterator()
Methode bereitgestellt haben . Die Implementierung vonstream()
inCollection
ist nur:Jeder Client kann den gewünschten Stream von einem
Iterable
mit erhalten:Am Ende schlossen wir , dass das Hinzufügen
stream()
zuIterable
einem Fehler wäre.quelle
Iterable<Integer>
(ich denke, Sie sprechen davon?) Einen zurückgeben möchteIntStream
. Wäre das iterable dann nicht lieber einPrimitiveIterator.OfInt
? Oder meinst du vielleicht einen anderen Anwendungsfall?Stream.of(Iterable)
, die die Methode zumindest durch Lesen der API-Dokumentation einigermaßen auffindbar machen würde - als jemand, der nie wirklich mit den Interna von Streams gearbeitet hat, würde ich nie selbst sah aufStreamSupport
, die in der Dokumentation beschrieben wird als „Low-Level - Operationen“ bietet die „vor allem für Bibliothek Autoren“ sind.Ich habe in mehreren Lambda-Mailinglisten des Projekts Nachforschungen angestellt und einige interessante Diskussionen gefunden.
Ich habe bisher keine zufriedenstellende Erklärung gefunden. Nachdem ich das alles gelesen hatte, kam ich zu dem Schluss, dass es nur eine Auslassung war. Aber Sie können hier sehen, dass es im Laufe der Jahre während des Entwurfs der API mehrmals diskutiert wurde.
Lambda Libs Spec Experts
Ich habe eine Diskussion darüber in der Mailingliste von Lambda Libs Spec Experts gefunden :
Unter Iterable / Iterator.stream () sagte Sam Pullara:
Und dann antwortete Brian Goetz :
Und später
Frühere Diskussionen in der Lambda-Mailingliste
Dies ist möglicherweise nicht die Antwort, nach der Sie suchen, aber in der Projekt-Lambda-Mailingliste wurde dies kurz besprochen. Vielleicht hilft dies, eine breitere Diskussion zu diesem Thema anzuregen.
In den Worten von Brian Goetz unter Streams von Iterable :
Widerspruch?
Es sieht jedoch so aus, als ob die Diskussion auf den Änderungen basiert, die die Expertengruppe am ursprünglichen Design von Streams vorgenommen hat, das ursprünglich auf Iteratoren basierte.
Trotzdem ist es interessant festzustellen, dass in einer Schnittstelle wie Collection die Stream-Methode wie folgt definiert ist:
Dies könnte genau derselbe Code sein, der in der Iterable-Schnittstelle verwendet wird.
Deshalb habe ich gesagt, dass diese Antwort wahrscheinlich nicht zufriedenstellend, aber dennoch interessant für die Diskussion ist.
Nachweis von Refactoring
Wenn Sie mit der Analyse in der Mailingliste fortfahren, sieht es so aus, als ob sich die splitIterator-Methode ursprünglich in der Collection-Oberfläche befand, und irgendwann im Jahr 2013 wurde sie auf Iterable verschoben.
Ziehen Sie splitIterator von Collection nach Iterable .
Schlussfolgerung / Theorien?
Dann besteht die Möglichkeit, dass das Fehlen der Methode in Iterable nur eine Auslassung ist, da es so aussieht, als hätten sie auch die Stream-Methode verschieben sollen, wenn sie den splitIterator von Collection nach Iterable verschoben haben.
Wenn es andere Gründe gibt, sind diese nicht offensichtlich. Hat noch jemand andere Theorien?
quelle
spliterator()
derIterable
, dann werden alle Ausgaben dort festgelegt sind, und Sie können trivialer implementierenstream()
undparallelStream()
..Wenn Sie die Größe kennen, die Sie verwenden können
java.util.Collection
, um diestream()
Methode bereitzustellen:Und dann:
Ich hatte das gleiche Problem und war überrascht, dass meine
Iterable
ImplementierungAbstractCollection
durch einfaches Hinzufügen dersize()
Methode sehr einfach auf eine Implementierung erweitert werden konnte (zum Glück hatte ich die Größe der Sammlung :-)Sie sollten auch in Betracht ziehen, zu überschreiben
Spliterator<E> spliterator()
.quelle