Zastanawiam się, dlaczego Iterable
interfejs nie zapewnia metod stream()
i parallelStream()
. Rozważ następującą klasę:
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();
}
}
Jest to realizacja ręku jak można mieć karty w ręku podczas gry karcianej Game.
Zasadniczo otacza a List<Card>
, zapewnia maksymalną pojemność i oferuje kilka innych przydatnych funkcji. Lepiej jest go wdrożyć bezpośrednio jako List<Card>
.
Teraz, dla wygody, pomyślałem, że fajnie byłoby zaimplementować Iterable<Card>
takie, że możesz użyć ulepszonych pętli for, jeśli chcesz nad nimi zapętlić. (Moja Hand
klasa zapewnia również get(int index)
metodę, dlatego Iterable<Card>
moim zdaniem jest to uzasadnione).
Iterable
Interfejs zapewnia następujące (w lewo na 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);
}
}
Teraz możesz uzyskać strumień z:
Stream<Hand> stream = StreamSupport.stream(hand.spliterator(), false);
Tak więc na prawdziwe pytanie:
- Dlaczego
Iterable<T>
nie zapewnia domyślnych metod, które się wdrożąstream()
iparallelStream()
nie widzę nic, co uczyniłoby to niemożliwym lub niechcianym?
Znalazłem podobne pytanie: Dlaczego Stream <T> nie implementuje Iterable <T>?
Co dziwnie sugeruje, że można to zrobić na odwrót.
źródło
break;
wykonać iterację? (Ok,Stream.findFirst()
może to być rozwiązanie, ale może nie spełniać wszystkich potrzeb ...)Odpowiedzi:
To nie było pominięciem; szczegółowo omówiono listę EG w czerwcu 2013 r.
Ostateczna dyskusja grupy ekspertów jest zakorzeniona w tym wątku .
Chociaż wydawało się to „oczywiste” (początkowo nawet dla grupy ekspertów),
stream()
wydawało się , że ma to sensIterable
, fakt, żeIterable
był tak ogólny, stał się problemem, ponieważ oczywisty podpis:nie zawsze było to, czego chciałeś. Niektóre rzeczy, które były
Iterable<Integer>
raczej mają ich sposób strumień zwracaćIntStream
, na przykład. Ale umieszczeniestream()
metody tak wysoko w hierarchii uniemożliwiłoby to. Zamiast więc zrobiliśmy to naprawdę łatwe do wykonaniaStream
ze związkuIterable
, dostarczającspliterator()
metody. Implementacjastream()
wCollection
jest po prostu:Każdy klient może uzyskać żądany strumień
Iterable
z:W końcu doszliśmy do wniosku, że dodawanie
stream()
doIterable
byłoby błędem.źródło
Iterable<Integer>
(myślę, że mówisz?) Chciałbyś zwrócićIntStream
. Czy zatem iterowalność raczej nie byłabyPrimitiveIterator.OfInt
? A może masz na myśli inny przypadek użycia?Stream.of(Iterable)
metoda statyczna , która przynajmniej uczyniłaby tę metodę racjonalnie możliwą do wykrycia przez przeczytanie dokumentacji API - jako kogoś, kto nigdy tak naprawdę nie pracował z elementami wewnętrznymi strumieni, których nigdy nie nawet spojrzał na toStreamSupport
, co jest opisane w dokumentacji jako zapewniające „operacje niskiego poziomu”, które są „głównie dla twórców bibliotek”.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ł:
A potem Brian Goetz odpowiedział :
I później
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 :
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:
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?
źródło
spliterator()
zIterable
, wówczas wszystkie kwestie nie są stałe i można trywialnie wdrożeniastream()
iparallelStream()
..Jeśli znasz rozmiar, którego możesz użyć,
java.util.Collection
który zapewniastream()
metodę:I wtedy:
Napotkałem ten sam problem i byłem zaskoczony, że moją
Iterable
implementację można bardzo łatwo rozszerzyć naAbstractCollection
implementację, po prostu dodającsize()
metodę (na szczęście miałem rozmiar kolekcji :-)Należy również rozważyć zastąpienie
Spliterator<E> spliterator()
.źródło