W Javie 8 istnieje Stream.collect
możliwość agregacji zbiorów. W Kotlinie nie istnieje to w ten sam sposób, poza tym, że może być zbiorem funkcji rozszerzenia w stdlib. Ale nie jest jasne, jakie są odpowiedniki dla różnych przypadków użycia.
Na przykład na górze JavaDocCollectors
znajdują się przykłady napisane dla Java 8, a podczas przenoszenia ich do Kolina nie można używać klas Java 8 w innej wersji JDK, więc prawdopodobnie powinny być napisane inaczej.
Jeśli chodzi o zasoby online pokazujące przykłady kolekcji Kotlin, są one zwykle trywialne i tak naprawdę nie porównują się do tych samych przypadków użycia. Jakie są dobre przykłady, które naprawdę pasują do przypadków, takich jak udokumentowane dla Java 8 Stream.collect
? Oto lista:
- Gromadzić nazwy na liście
- Zbierz nazwy w TreeSet
- Konwertuj elementy na ciągi i łącz je, oddzielając je przecinkami
- Oblicz sumę wynagrodzeń pracownika
- Grupuj pracowników według działów
- Oblicz sumę wynagrodzeń według działów
- Podziel uczniów na zaliczenia i porażki
Szczegółowe informacje w JavaDoc znajdują się powyżej.
Uwaga: to pytanie zostało celowo napisane i udzielone przez autora ( pytania z odpowiedziami ), aby idiomatyczne odpowiedzi na najczęściej zadawane tematy Kotlina były obecne w SO. Również w celu wyjaśnienia niektórych naprawdę starych odpowiedzi napisanych dla alpha Kotlina, które nie są dokładne dla dzisiejszego Kotlina.
źródło
collect(Collectors.toList())
lub podobny, możesz trafić w ten problem: stackoverflow.com/a/35722167/3679676 (problem, z obejściem)Odpowiedzi:
W standardzie Kotlin znajdują się funkcje: uśredniania, liczenia, wyodrębniania, filtrowania, wyszukiwania, grupowania, łączenia, mapowania, min, maks., Partycjonowania, krojenia, sortowania, sumowania, do / z tablic, do / z list, do / z map , zjednoczenie, ko-iteracja, wszystkie paradygmaty funkcjonalne i wiele innych. Możesz więc używać ich do tworzenia małych 1-liniowych programów i nie trzeba używać bardziej skomplikowanej składni Java 8.
Myślę, że jedyną rzeczą, której brakuje we wbudowanejCollectors
klasie Java 8, jest podsumowanie (ale w innej odpowiedzi na to pytanie jest proste rozwiązanie) .Jedną z rzeczy, której brakuje w obu przypadkach, jest grupowanie według liczby, co widać w innej odpowiedzi Przepełnienie stosu i ma również prostą odpowiedź. Innym interesującym przypadkiem jest również ten z przepełnienia stosu: Idiomatyczny sposób na rozlanie sekwencji na trzy listy za pomocą Kotlina . A jeśli chcesz stworzyć cośStream.collect
w innym celu, zobacz Custom Stream.collect w KotlinEDYCJA 11.08.2017: Operacje zbierania fragmentów / okien zostały dodane w kotlin 1.2 M2, patrz https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-2-m2-is-out/
Zawsze dobrze jest zapoznać się z API Reference dla kotlin.collections jako całości przed utworzeniem nowych funkcji, które już tam mogą istnieć.
Oto niektóre konwersje z
Stream.collect
przykładów Java 8 na odpowiednik w Kotlin:Gromadzić nazwy na liście
Konwertuj elementy na ciągi i łącz je, oddzielając je przecinkami
Oblicz sumę wynagrodzeń pracownika
Grupuj pracowników według działów
Oblicz sumę wynagrodzeń według działów
Podziel uczniów na zaliczenia i porażki
Nazwiska członków męskich
Grupuj nazwiska członków w wykazie według płci
Filtruj listę do innej listy
Znajdowanie najkrótszego ciągu znaków na liście
Zliczanie elementów na liście po zastosowaniu filtra
i tak dalej ... We wszystkich przypadkach naśladowanie nie wymagało specjalnego składania, zmniejszania ani innych funkcji
Stream.collect
. Jeśli masz dalsze przypadki użycia, dodaj je w komentarzach, a my zobaczymy!O lenistwie
Jeśli chcesz leniwie przetworzyć łańcuch, możesz przekonwertować go na
Sequence
usingasSequence()
przed łańcuchem. Na końcu łańcucha funkcji zwykle kończy się również znakiem „Sequence
a”. Następnie można użyćtoList()
,toSet()
,toMap()
lub jakaś inna funkcja urzeczywistnieniaSequence
na końcu.Dlaczego nie ma żadnych typów?!?
Zauważysz, że przykłady Kotlin nie określają typów. Jest tak, ponieważ Kotlin ma pełne wnioskowanie o typach i jest całkowicie bezpieczny podczas kompilacji. Bardziej niż Java, ponieważ ma również typy zerowalne i może pomóc zapobiec przerażającemu NPE. To w Kotlinie:
jest taki sam jak:
Kotlin bo nie wie, co
people
jest, i topeople.age
jestInt
zatem wyrazem filtr pozwala tylko porównania doInt
, apeople.name
toString
dlategomap
krok wytwarzaList<String>
(tylko do odczytuList
zString
).Teraz, jeśli
people
to możliwenull
, jakoList<People>?
:Zwraca wartość
List<String>?
, która wymagałaby sprawdzenia wartości null ( lub użyj jednego z innych operatorów Kotlin dla wartości zerowalnych, zobacz ten idiomatyczny sposób Kotlina, aby radzić sobie z wartościami zerowalnymi, a także Idiomatyczny sposób obsługi wartości zerowej lub pustej listy w Kotlinie )Zobacz też:
źródło
Aby uzyskać dodatkowe przykłady, oto wszystkie przykłady z samouczka strumienia Java 8 przekonwertowanego na Kotlin. Tytuł każdego przykładu pochodzi z artykułu źródłowego:
Jak działają strumienie
Różne rodzaje strumieni # 1
lub utwórz funkcję rozszerzenia na łańcuchu o nazwie ifPresent:
Zobacz także:
apply()
funkcjaZobacz także: Funkcje rozszerzeń
Zobacz także:
?.
operator Safe Call i ogólnie zerowalność : w Kotlin, co jest idiomatycznym sposobem radzenia sobie z wartościami zerowymi, odwoływania się do nich lub konwertowania ichRóżne rodzaje strumieni # 2
Różne rodzaje strumieni # 3
Różne rodzaje strumieni # 4
Różne rodzaje strumieni # 5
Różne rodzaje strumieni # 6
Różne rodzaje strumieni # 7
Dlaczego warto się zamawiać?
Ta sekcja samouczka Java 8 Stream jest taka sama dla Kotlin i Java.
Ponowne użycie strumieni
W Kotlinie zależy od rodzaju zbioru, czy można go spożywać więcej niż jeden raz. A
Sequence
generuje nowy iterator za każdym razem i jeśli nie zapewni „użyj tylko raz”, może zresetować do początku za każdym razem, gdy jest podejmowane działanie. Dlatego, mimo że w strumieniu Java 8 nie działa, ale działa w Kotlin:I w Javie, aby uzyskać takie samo zachowanie:
Dlatego w Kotlin dostawca danych decyduje, czy może zresetować i dostarczyć nowy iterator, czy nie. Ale jeśli chcesz celowo ograniczyć
Sequence
iterację do jednego czasu, możesz użyćconstrainOnce()
funkcjiSequence
w następujący sposób:Zaawansowane operacje
Zbierz przykład 5 (tak, pominąłem te, które już znalazły się w innej odpowiedzi)
Na marginesie, w Kotlin możemy tworzyć proste klasy danych i tworzyć instancję danych testowych w następujący sposób:
Zbierz przykład # 6
Ok, bardziej interesujący przypadek tutaj dla Kotlina. Najpierw złe odpowiedzi, aby zbadać warianty tworzenia
Map
zbioru / sekwencji:A teraz poprawna odpowiedź:
Musieliśmy tylko połączyć pasujące wartości, aby zwinąć listy i zapewnić transformator
jointToString
do przenoszenia zPerson
instancji doPerson.name
.Zbierz przykład 7
Ok, można to łatwo zrobić bez niestandardowego rozwiązania
Collector
, więc rozwiążmy to na Kotlin, a następnie wymyślmy nowy przykład, który pokazuje, jak wykonać podobny proces, dlaCollector.summarizingInt
którego w Kotlinie nie ma natywnej metody.To nie moja wina, że wybrali trywialny przykład !!! Ok, oto nowa
summarizingInt
metoda dla Kotlina i pasująca próbka:Przykład podsumowania
Ale lepiej jest utworzyć funkcję rozszerzenia, w rzeczywistości 2, aby dopasować style w Kotlin stdlib:
Teraz masz dwa sposoby korzystania z nowych
summarizingInt
funkcji:Wszystkie dają te same wyniki. Możemy również utworzyć to rozszerzenie do pracy
Sequence
i dla odpowiednich typów pierwotnych.Dla zabawy porównaj kod JDK Java i niestandardowy kod Kotlin wymagany do zaimplementowania tego podsumowania.
źródło
.map { it.substring(1).toInt() }
: jak wiadomo, dobrze wywnioskowany typ to moc kotlin.W niektórych przypadkach trudno uniknąć połączeń telefonicznych
collect(Collectors.toList())
lub podobnych. W takich przypadkach można szybciej zmienić na ekwiwalent Kotlin za pomocą funkcji rozszerzeń, takich jak:Następnie możesz po prostu
stream.toList()
lubstream.asSequence()
wrócić do interfejsu API Kotlin. Przypadek taki jakFiles.list(path)
zmusza cię doStream
momentu, w którym możesz go nie chcieć, a te rozszerzenia mogą pomóc Ci wrócić do standardowych kolekcji i interfejsu API Kotlin.źródło
Więcej o lenistwie
Weźmy przykładowe rozwiązanie dla „Oblicz sumę wynagrodzeń według działów” podane przez Jaysona:
Aby uczynić to leniwym (tj. Uniknąć tworzenia mapy pośredniej w
groupBy
kroku), nie można jej użyćasSequence()
. Zamiast tego musimy używaćgroupingBy
ifold
obsługiwać:Dla niektórych osób może to być nawet bardziej czytelne, ponieważ nie masz do czynienia z wpisami map:
it.value
część rozwiązania była dla mnie również myląca.Ponieważ jest to częsty przypadek i za
fold
każdym razem wolimy nie wypisywać , lepiej może być zapewnienie ogólnejsumBy
funkcjiGrouping
:abyśmy mogli po prostu napisać:
źródło