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:
Ich habe mit Brian zusammengearbeitet, um herauszufinden, wie die Limit / Substream-Funktionalität [1] implementiert werden kann, und er schlug vor, dass die Konvertierung auf Iterator der richtige Weg ist. Ich hatte über diese Lösung nachgedacht, aber keinen offensichtlichen Weg gefunden, einen Iterator in einen Stream umzuwandeln. Es stellt sich heraus, dass es dort drin ist. Sie müssen nur zuerst den Iterator in einen Spliterator und dann den Spliterator in einen Stream konvertieren. Dies bringt mich dazu, noch einmal zu überlegen, ob diese direkt an einem von Iterable / Iterator oder an beiden hängen sollen.
Mein Vorschlag ist, es zumindest auf Iterator zu haben, damit Sie sich sauber zwischen den beiden Welten bewegen können, und es wäre auch leicht zu entdecken, anstatt es tun zu müssen:
Streams.stream (Spliterators.spliteratorUnknownSize (Iterator, Spliterator.ORDERED))
Und dann antwortete Brian Goetz :
Ich denke, Sams Punkt war, dass es viele Bibliotheksklassen gibt, die Ihnen einen Iterator geben, aber Sie nicht unbedingt Ihren eigenen Spliterator schreiben lassen. Sie können also nur den Stream (spliteratorUnknownSize (Iterator)) aufrufen. Sam schlägt vor, dass wir Iterator.stream () definieren, um dies für Sie zu tun.
Ich möchte die Methoden stream () und spliterator () für Bibliotheksschreiber / fortgeschrittene Benutzer beibehalten.
Und später
"Da das Schreiben eines Spliterators einfacher ist als das Schreiben eines Iterators, würde ich es vorziehen, nur einen Spliterator anstelle eines Iterators zu schreiben (Iterator ist so 90er Jahre :)"
Sie verpassen jedoch den Punkt. Es gibt Myriaden von Klassen gibt, die bereits Hand Sie einen Iterator. Und viele von ihnen sind nicht spliterator-fähig.
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 :
Zurück gehen...
Es gibt viele Möglichkeiten, einen Stream zu erstellen. Je mehr Informationen Sie zur Beschreibung der Elemente haben, desto mehr Funktionalität und Leistung kann Ihnen die Streams-Bibliothek bieten. In der Reihenfolge der wenigsten bis zu den meisten Informationen sind dies:
Iterator
Iterator + Größe
Spliterator
Spliterator, der seine Größe kennt
Spliterator, der seine Größe kennt und außerdem weiß, dass alle Sub-Splits ihre Größe kennen.
(Einige mögen überrascht sein, dass wir Parallelität sogar aus einem dummen Iterator extrahieren können, wenn Q (Arbeit pro Element) nicht trivial ist.)
Wenn Iterable eine stream () -Methode hätte, würde es nur einen Iterator mit einem Spliterator ohne Größeninformationen umschließen. Die meisten Dinge, die iterierbar sind, haben jedoch Größeninformationen . Das heißt, wir bedienen mangelhafte Streams. Das ist nicht so gut
Ein Nachteil der von Stephen hier beschriebenen API-Praxis, Iterable anstelle von Collection zu akzeptieren, besteht darin, dass Sie Dinge durch eine "kleine Pipe" zwingen und daher Größeninformationen verwerfen, wenn dies nützlich sein könnte. Das ist in Ordnung, wenn Sie nur für jedes tun, aber wenn Sie mehr tun möchten, ist es besser, wenn Sie alle gewünschten Informationen beibehalten können.
Die von Iterable bereitgestellte Standardeinstellung wäre in der Tat beschissen - sie würde die Größe verwerfen, obwohl die überwiegende Mehrheit der Iterables diese Informationen kennt.
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:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
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?