Przeprowadziłem dochodzenie na kilku listach mailingowych projektu lambda i myślę, że znalazłem kilka interesujących dyskusji.
Jak dotąd nie znalazłem zadowalającego wyjaśnienia. Po przeczytaniu tego wszystkiego doszedłem do wniosku, że to tylko pominięcie. Ale widać tutaj, że omawiano go kilka razy na przestrzeni lat podczas projektowania interfejsu API.
Lambda Libs Spec Experts
Dyskusję na ten temat znalazłem na liście dyskusyjnej Lambda Libs Spec Experts :
W części Iterable / Iterator.stream () Sam Pullara powiedział:
Pracowałem z Brianem nad tym, w jaki sposób można wdrożyć funkcjonalność limitu / podstrumienia [1], a on zasugerował, że konwersja do Iteratora jest właściwą drogą do tego. Myślałem o tym rozwiązaniu, ale nie znalazłem żadnego oczywistego sposobu, aby wziąć iterator i zamienić go w strumień. Okazuje się, że tam jest, wystarczy przekonwertować iterator na spliterator, a następnie przekonwertować spliterator na strumień. To skłania mnie do ponownego rozważenia, czy powinniśmy mieć te zawieszone bezpośrednio w jednym z Iterable / Iterator, czy w obu.
Sugeruję, aby przynajmniej mieć go na Iteratorze, abyś mógł swobodnie poruszać się między dwoma światami, a także byłoby łatwo go odkryć, niż robić:
Streams.stream (Spliterators.spliteratorUnknownSize (iterator, Spliterator.ORDERED))
A potem Brian Goetz odpowiedział :
Myślę, że Sam miał na myśli to, że istnieje wiele klas bibliotecznych, które dają ci iterator, ale niekoniecznie musisz pisać własnego spliteratora. Wszystko, co możesz zrobić, to strumień połączeń (spliteratorUnknownSize (iterator)). Sam sugeruje zdefiniowanie Iterator.stream (), aby zrobić to za Ciebie.
Chciałbym zachować metody stream () i spliterator () jako przeznaczone dla autorów bibliotek / zaawansowanych użytkowników.
I później
„Biorąc pod uwagę, że pisanie Spliteratora jest łatwiejsze niż pisanie Iteratora, wolałbym po prostu napisać Spliteratora zamiast Iteratora (Iterator jest taki z lat 90.”)
Jednak brakuje ci sensu. Istnieją setki klas, które już dają ci Iterator. I wiele z nich nie jest przystosowanych do spliteratora.
Poprzednie dyskusje na liście mailingowej Lambda
Być może nie jest to odpowiedź, której szukasz, ale na liście dyskusyjnej projektu Lambda zostało to krótko omówione. Być może pomaga to w szerszej dyskusji na ten temat.
Według słów Briana Goetza w Streams from Iterable :
Cofając się ...
Istnieje wiele sposobów tworzenia strumienia. Im więcej informacji na temat opisywania elementów, tym więcej funkcjonalności i wydajności może zapewnić biblioteka strumieni. W kolejności od co najmniej do większości informacji są to:
Iterator
Iterator + rozmiar
Spliterator
Spliterator, który zna jego rozmiar
Spliterator, który zna jego rozmiar, a ponadto wie, że wszystkie podziały znają swój rozmiar.
(Niektórzy mogą być zaskoczeni, gdy stwierdzimy, że możemy wydobyć paralelizm nawet z głupiego iteratora w przypadkach, gdy Q (praca na element) nie jest łatwe.)
Gdyby Iterable miał metodę stream (), po prostu owinąłby Iterator Spliteratorem, bez informacji o rozmiarze. Ale większość rzeczy, które są iterowalne , zawiera informacje o rozmiarze. Co oznacza, że obsługujemy niedobór strumieni. To nie jest takie dobre.
Jedną z wad praktyki API opisanej tutaj przez Stephena, polegającej na akceptowaniu Iterable zamiast Collection, jest to, że zmuszasz rzeczy przez „małą rurkę”, a zatem odrzucasz informacje o rozmiarze, gdy może to być przydatne. To dobrze, jeśli robisz to tylko dla każdego, ale jeśli chcesz zrobić więcej, lepiej jest, jeśli możesz zachować wszystkie potrzebne informacje.
Domyślne ustawienie dostarczone przez Iterable byłoby naprawdę gówniane - odrzuciłoby rozmiar, mimo że zdecydowana większość Iterable zna te informacje.
Sprzeczność?
Chociaż wygląda na to, że dyskusja opiera się na zmianach, które Grupa Ekspertów wprowadziła do początkowego projektu Strumieni, który początkowo był oparty na iteratorach.
Mimo to warto zauważyć, że w interfejsie takim jak Collection metoda stream jest zdefiniowana jako:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
Może to być dokładnie ten sam kod użyty w interfejsie Iterable.
Dlatego powiedziałem, że ta odpowiedź prawdopodobnie nie jest zadowalająca, ale nadal interesująca w dyskusji.
Dowody refaktoryzacji
Kontynuując analizę na liście mailingowej, wygląda na to, że metoda splitIterator była pierwotnie w interfejsie Collection, aw pewnym momencie w 2013 roku przenieśli ją do Iterable.
Pociągnij splitIterator z kolekcji do Iterable .
Wnioski / teorie?
Są zatem szanse, że brak metody w Iterable jest tylko pominięciem, ponieważ wygląda na to, że powinni również przenieść metodę stream, gdy przenieśli splitIterator z Collection do Iterable.
Jeśli istnieją inne powody, nie są one oczywiste. Ktoś inny ma inne teorie?