Bawiłem się lambdami Java 8, aby łatwo filtrować kolekcje. Ale nie znalazłem zwięzłego sposobu na uzyskanie wyniku jako nowej listy w ramach tej samej instrukcji. Oto moje najbardziej zwięzłe podejście do tej pory:
List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = new ArrayList<>();
sourceLongList.stream().filter(l -> l > 100).forEach(targetLongList::add);
Przykłady w sieci nie odpowiedziały na moje pytanie, ponieważ zatrzymały się bez wygenerowania nowej listy wyników. Musi być bardziej zwięzły sposób. Liczyłam, że Stream
klasa ma sposobów toList()
, toSet()
...
Czy istnieje sposób, aby zmienne targetLongList
można przypisać bezpośrednio w trzecim wierszu?
collections
lambda
java-8
java-stream
Daniel K.
źródło
źródło
sourceLongList
później, jestCollection.removeIf(…)
dla wygody.List<Long> targetLongList = sourceLongList.stream().collect(Collectors.toList());
Odpowiedzi:
To, co robisz, może być najprostszym sposobem, pod warunkiem, że Twój strumień pozostaje sekwencyjny - w przeciwnym razie będziesz musiał wcześniej wywołać funkcję sekwencyjną ()
forEach
.[późniejsza edycja: powodem, dla którego konieczne jest wywołanie funkcji sekwencyjnej (), jest to, że kod w jego obecnej postaci (
forEach(targetLongList::add)
) byłby bardziej ryzykowny, gdyby strumień był równoległy. Nawet wtedy nie osiągnie zamierzonego efektu, coforEach
jest wyraźnie niedeterministyczne - nawet w strumieniu sekwencyjnym kolejność przetwarzania elementów nie jest gwarantowana. Musisz użyć,forEachOrdered
aby zapewnić prawidłowe zamówienie. Intencją projektantów Stream API jest użycie kolektora w takiej sytuacji, jak poniżej.]Alternatywą jest
źródło
toList
. Odbywa się to poprzez umieszczenie następujących wśród importu pliku:static import java.util.stream.Collectors.toList;
. Następnie połączenie odbiera tylko.collect(toList())
.Collectors
klasy w Preferencjach -> Java -> Edytor -> Content Assist -> Ulubione . Następnie wystarczy wpisaćtoLi
w Ctr + Spacja, aby wypełnić IDEtoList
i dodać import statyczny.IntStream
niektóre inne prawie-ale-nie-całkiemStream
nie mają tejcollect(Collector)
metody i będziesz musiał zadzwonić,IntStream.boxed()
aby przekonwertować je na regularneStream
. Z drugiej strony, może po prostu chcesztoArray()
.sequential()
przedforEach
lub użyć „dla każdego zamówienia”Zaktualizowano:
Innym podejściem jest użycie
Collectors.toList
:Poprzednie rozwiązanie:
Innym podejściem jest użycie
Collectors.toCollection
:źródło
Collectors::toList
javadoc: „Nie ma żadnych gwarancji na rodzaj, zmienność, serializację lub bezpieczeństwo wątków zwróconej listy; jeśli wymagana jest większa kontrola nad zwracaną listą, użyjtoCollection(Supplier)
”.Lubię używać metody util, która zwraca kolektor,
ArrayList
gdy tego właśnie chcę.Myślę, że użycie tego rozwiązania
Collectors.toCollection(ArrayList::new)
jest trochę zbyt głośne w przypadku tak powszechnej operacji.Przykład:
Tą odpowiedzią chcę również zademonstrować, jak łatwo jest tworzyć niestandardowe kolektory i korzystać z nich, co jest ogólnie bardzo przydatne.
źródło
toList
jeśli chcesz na przykład zmodyfikować listę później w programie.toList
Dokumentacja mówi tak: „Nie ma żadnych gwarancji co do rodzaju, zmienności, serializability lub nitki bezpieczeństwa listy zwrócony, jeśli potrzebna jest większa kontrola nad zwróconej listy, użyjtoCollection
”. . Moja odpowiedź pokazuje sposób, aby uczynić to wygodniejszym w zwykłym przypadku.Jeśli masz tablicę prymitywów, możesz użyć pierwotnych kolekcji dostępnych w Eclipse Collections .
Jeśli nie możesz zmienić sourceLongList z
List
:Jeśli chcesz użyć
LongStream
:Uwaga: Jestem współtwórcą kolekcji Eclipse.
źródło
Trochę bardziej wydajny sposób (unikaj tworzenia listy źródłowej i automatycznego rozpakowywania przez filtr):
źródło
To jest połączenie, którego możesz użyć do konwersji dowolnego strumienia na listę.
bardziej konkretnie:
od:
https://www.geeksforgeeks.org/collectors-tolist-method-in-java-with-examples/
źródło
Jeśli nie przeszkadza przy użyciu bibliotek 3rd party, AOL Cyklop reagują lib (ujawnienie jestem specjalista) posiada rozszerzenia dla wszystkich JDK Kolekcja typów, w tym listy . Interfejs ListX rozszerza java.util.List i dodaje wiele przydatnych operatorów, w tym filtr.
Możesz po prostu napisać
ListX można również utworzyć z istniejącej listy (poprzez ListX.fromIterable)
źródło
Istnieje inny wariant metody kolekcjonowania zapewniany przez klasę LongStream, podobnie jak klasy IntStream i DoubleStream.
Wykonuje zmienną operację redukcji na elementach tego strumienia. Zmienna redukcja to taka, w której zmniejszona wartość jest zmiennym pojemnikiem wyników, takim jak ArrayList, a elementy są włączane przez aktualizację stanu wyniku zamiast zastępowania wyniku. Daje to wynik równoważny z:
Podobnie jak redukcja (long, LongBinaryOperator), operacje zbierania mogą być równoległe bez konieczności dodatkowej synchronizacji. To jest operacja terminalowa.
Odpowiedź na twoje pytanie za pomocą tej metody zbierania jest następująca:
Poniżej znajduje się wariant referencyjny metody, który jest dość sprytny, ale niektóre trudne do zrozumienia:
Poniżej będzie wariant HashSet:
Podobnie wariant LinkedList wygląda następująco:
źródło
Jeśli ktoś (jak ja) szuka sposobów radzenia sobie z obiektami zamiast typów pierwotnych, użyj
mapToObj()
drukuje:
źródło
źródło
Oto kod AbacusUtil
Ujawnienie : Jestem programistą AbacusUtil.
źródło
com.landawn.abacus.util.stream.LongStream
orLongStreamEx
in AbacusUtilMożesz przepisać kod jak poniżej:
źródło
Aby zebrać na zmiennej liście:
Aby zebrać na niezmiennej liście:
Objaśnienie
collect
z JavaDoc :źródło
Jeśli nie użyjesz,
parallel()
to zadziałaźródło
collect
a następnie nie zapisać wartości zwracanej. W takim przypadku możesz użyćforEach
zamiast tego. Ale to wciąż złe rozwiązanie.