2014-09-02 11 views
10

Zastanawiam się, czy istnieje preferowany sposób przejścia ze strumienia list do kolekcji zawierającej elementy wszystkich list w strumieniu. mogę myśleć dwa sposoby, aby tam dostać:Czy istnieje preferowany sposób pobierania strumienia list do listy płaskiej?

final Stream<List<Integer>> stream = Stream.empty(); 
final List<Integer> one = stream.collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll); 
final List<Integer> two = stream.flatMap(List::stream).collect(Collectors.toList()); 

Druga opcja wygląda o wiele ładniejszy do mnie, ale myślę, że pierwszy z nich jest bardziej wydajny w równoległych strumieni. Czy istnieją dalsze argumenty za lub przeciw jednej z dwóch metod?

Odpowiedz

9

Główna różnica polega na tym, że flatMap to intermediate operation., natomiast collect to terminal operation.

Więc flatMap jest jedynym sposobem przetwarzać spłaszczone elementy strumieniowych jeśli chcesz robić inne czynności niż collect ing natychmiast.

Kolejne jest trudny do odczytania, ponieważ posiada dwa identyczne odniesienia do metod: ArrayList::addAll z zupełnie inną semantyką.

Jeśli chodzi o przetwarzanie równoległe, Twoje przypuszczenie jest błędne. Pierwsza z nich ma mniejsze możliwości przetwarzania równoległego, ponieważ polega na ArrayList.addAll zastosowanej do elementów strumienia (podlist), które nie mogą być podzielone na równoległe pod-kroki. W przeciwieństwie do tego, Collectors.toList() zastosowane do flatMap może przetwarzać równolegle pozycje pod-listy, jeśli konkretny napotkany w strumieniu List s je obsługuje. Ale będzie to miało znaczenie tylko wtedy, gdy masz raczej niewielki strumień raczej dużych pod-list.

Jedyną wadą flatMap jest tworzenie strumienia pośredniego, który dodaje narzut w przypadku, gdy masz wiele bardzo małych pod-list.

Ale w twoim przykładzie strumień jest pusty, więc nie ma znaczenia (scnr).

+0

Czy mógłbyś wyjaśnić, dlaczego pierwsza wersja nie działałaby dobrze w równoległym strumieniu? Operacje pośrednie przed zbieraniem mogą być wykonywane równolegle i kilka ArrayLists może być utrzymanych za pomocą funkcji akumulatora (drugi parametr zbierania). Następnie łącznik (trzeci parametr) zostanie użyty do zebrania wszystkich elementów w jedną dużą ArrayList. (W tym przypadku obie funkcje będą oczywiście takie same, ale użyte w inny sposób). – muued

+1

Równoległość jest taka sama w obu wersjach w odniesieniu do przetwarzania ** 'Stream' **, czyli * zewnętrznego * strumienia. Ale w drugiej wersji spłaszczony strumień składa się z elementów ** listy dodatkowej **, która pozwala na dzielenie operacji w środku podlist, jeśli jest to wykonalne. Jest to niemożliwe w pierwszej wersji. Jak już wspomniano, jest to istotne tylko wtedy, gdy strumień składa się z kilku raczej dużych podlist (i jeśli różnią się one rozmiarem). Ponieważ nie masz pośrednich operacji między 'flatMap' i' collect', wpływa to tylko na 'collect', więc różnica może być bardzo mała. – Holger

+0

W porządku, jeśli były niezbędne operacje pomiędzy 'flatMap' i' collect', zdecydowanie nie należy używać pierwszej wersji. Nie brałem tego pod uwagę. Dzięki za odpowiedź – muued

4

Myślę, że zamiar opcji drugiej jest dużo jaśniejszy niż wariant pierwszej. Zajęło mi kilka sekund, aby dowiedzieć się, co dzieje się z pierwszym, nie wygląda to "dobrze" - choć wydaje się prawidłowe. Opcja druga była dla mnie bardziej oczywista.

Zasadniczo intencją tego, co robisz, jest flatmap. Jeśli tak jest, spodziewam się, że zamiast zwykłej metody addAll() użyje się płaskiego mapowania.

Powiązane problemy