In Java 8 gibt Stream.collect
es Aggregationen für Sammlungen. In Kotlin existiert dies nicht auf die gleiche Weise, außer vielleicht als Sammlung von Erweiterungsfunktionen in der stdlib. Es ist jedoch nicht klar, welche Äquivalenzen für verschiedene Anwendungsfälle gelten.
Am oberen Rand des JavaDoc fürCollectors
befinden sich beispielsweise Beispiele für Java 8, und wenn Sie sie nach Kolin portieren , können Sie die Java 8-Klassen nicht verwenden, wenn Sie eine andere JDK-Version verwenden. Daher sollten sie wahrscheinlich anders geschrieben werden.
In Bezug auf Online-Ressourcen, die Beispiele für Kotlin-Sammlungen zeigen, sind sie in der Regel trivial und nicht wirklich mit denselben Anwendungsfällen vergleichbar. Was sind gute Beispiele, die wirklich zu den für Java 8 dokumentierten Fällen passen Stream.collect
? Die Liste dort ist:
- Sammeln Sie Namen in einer Liste
- Sammeln Sie Namen in einem TreeSet
- Konvertieren Sie Elemente in Zeichenfolgen und verketten Sie sie durch Kommas getrennt
- Berechnen Sie die Summe der Gehälter des Mitarbeiters
- Mitarbeiter der Gruppe nach Abteilungen
- Berechnen Sie die Summe der Gehälter nach Abteilung
- Teilen Sie die Schüler in Bestehen und Nichtbestehen auf
Mit Details im oben verlinkten JavaDoc.
Hinweis: Diese Frage wurde absichtlich vom Autor geschrieben und beantwortet ( Selbst beantwortete Fragen ), sodass die idiomatischen Antworten auf häufig gestellte Kotlin-Themen in SO vorhanden sind. Auch um einige wirklich alte Antworten zu klären, die für Alphas von Kotlin geschrieben wurden und für das heutige Kotlin nicht korrekt sind.
quelle
collect(Collectors.toList())
oder ähnliches, kann dieses Problem auftreten: stackoverflow.com/a/35722167/3679676 (das Problem mit Problemumgehungen)Antworten:
In der Kotlin-Standardliste gibt es Funktionen für Durchschnitt, Anzahl, Unterscheidung, Filtern, Finden, Gruppieren, Verbinden, Zuordnen, Min, Max, Partitionieren, Schneiden, Sortieren, Summieren, zu / von Arrays, zu / von Listen, zu / von Karten , Vereinigung, Ko-Iteration, alle funktionalen Paradigmen und mehr. Sie können diese also verwenden, um kleine 1-Liner zu erstellen, und Sie müssen nicht die kompliziertere Syntax von Java 8 verwenden.
Ich denke, das einzige, was in der integrierten Java 8-Collectors
Klasse fehlt, ist die Zusammenfassung (aber in einer anderen Antwort auf diese Frage ist eine einfache Lösung) .Eine Sache, die in beiden fehlt, ist das Stapeln nach Anzahl, was in einer anderen Antwort zum Stapelüberlauf zu sehen ist und auch eine einfache Antwort enthält. Ein weiterer interessanter Fall ist dieser ebenfalls aus Stack Overflow: Idiomatischer Weg, um mit Kotlin eine Sequenz in drei Listen zu verschütten . Wenn Sie etwasStream.collect
für einen anderen Zweck erstellen möchten, lesen Sie Benutzerdefinierte Stream.collect in KotlinBEARBEITEN 11.08.2017: In kotlin 1.2 M2 wurden Sammelvorgänge mit Chunked / Window hinzugefügt, siehe https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-2-m2-is-out/
Es ist immer gut, die API-Referenz für kotlin.collections als Ganzes zu durchsuchen, bevor Sie neue Funktionen erstellen, die dort möglicherweise bereits vorhanden sind.
Hier sind einige Konvertierungen von Java 8-
Stream.collect
Beispielen in das Äquivalent in Kotlin:Sammeln Sie Namen in einer Liste
Konvertieren Sie Elemente in Zeichenfolgen und verketten Sie sie durch Kommas getrennt
Berechnen Sie die Summe der Gehälter des Mitarbeiters
Mitarbeiter der Gruppe nach Abteilungen
Berechnen Sie die Summe der Gehälter nach Abteilung
Teilen Sie die Schüler in Bestehen und Nichtbestehen auf
Namen männlicher Mitglieder
Gruppennamen der Mitglieder im Kader nach Geschlecht
Filtern Sie eine Liste in eine andere Liste
Suche nach der kürzesten Zeichenfolge einer Liste
Zählen von Elementen in einer Liste, nachdem der Filter angewendet wurde
und weiter geht's ... In allen Fällen war keine spezielle Falz-, Reduzierungs- oder andere Funktionalität erforderlich, um nachzuahmen
Stream.collect
. Wenn Sie weitere Anwendungsfälle haben, fügen Sie diese in die Kommentare ein und wir können sehen!Über Faulheit
Wenn Sie eine Kette verzögert verarbeiten möchten, können Sie
Sequence
sieasSequence()
vor der Kette in eine Verwendung konvertieren . Am Ende der Funktionskette erhalten Sie normalerweiseSequence
auch ein. Dann können Sie verwendentoList()
,toSet()
,toMap()
oder eine andere Funktion die materialisierenSequence
am Ende.Warum gibt es keine Typen?!?
Sie werden feststellen, dass in den Kotlin-Beispielen die Typen nicht angegeben sind. Dies liegt daran, dass Kotlin über eine vollständige Typinferenz verfügt und zur Kompilierungszeit vollständig typsicher ist. Mehr als Java, da es auch nullfähige Typen hat und dabei helfen kann, die gefürchtete NPE zu verhindern. Also das in Kotlin:
ist das gleiche wie:
Weil Kotlin weiß, was
people
ist, und daspeople.age
istInt
daher der Filterausdruck nur einen Vergleich mit einemInt
, und daspeople.name
ist ein,String
dahermap
erzeugt der Schritt einList<String>
(schreibgeschütztList
vonString
).Nun, wenn
people
es möglich wärenull
, wieList<People>?
damals:Gibt eine zurück
List<String>?
, die auf Null geprüft werden müsste ( oder verwenden Sie einen der anderen Kotlin-Operatoren für nullfähige Werte. Siehe diese Kotlin-idiomatische Methode zum Umgang mit nullbaren Werten und auch die idiomatische Methode zum Behandeln von nullbaren oder leeren Listen in Kotlin ).Siehe auch:
quelle
Weitere Beispiele finden Sie in allen Beispielen aus dem in Kotlin konvertierten Java 8 Stream Tutorial . Der Titel jedes Beispiels leitet sich aus dem Quellartikel ab:
Wie Streams funktionieren
Verschiedene Arten von Streams # 1
Oder erstellen Sie eine Erweiterungsfunktion für den String ifPresent:
Siehe auch:
apply()
FunktionSiehe auch: Erweiterungsfunktionen
Siehe auch:
?.
Safe Call-Operator und allgemeine Nullbarkeit: Was ist in Kotlin die idiomatische Methode, um mit nullbaren Werten umzugehen, sie zu referenzieren oder zu konvertieren ?Verschiedene Arten von Streams # 2
Verschiedene Arten von Streams # 3
Verschiedene Arten von Streams # 4
Verschiedene Arten von Streams # 5
Verschiedene Arten von Streams # 6
Verschiedene Arten von Streams # 7
Warum bestellen Angelegenheiten
Dieser Abschnitt des Java 8 Stream-Lernprogramms ist für Kotlin und Java identisch.
Streams wiederverwenden
In Kotlin hängt es von der Art der Sammlung ab, ob sie mehrmals konsumiert werden kann. A
Sequence
generiert jedes Mal einen neuen Iterator, und wenn es nicht "nur einmal verwenden" behauptet, kann es jedes Mal, wenn es bearbeitet wird, auf den Start zurückgesetzt werden. Daher schlägt im Java 8-Stream zwar Folgendes fehl, funktioniert aber in Kotlin:Und in Java, um das gleiche Verhalten zu erhalten:
Daher entscheidet der Anbieter der Daten in Kotlin, ob er zurückgesetzt und ein neuer Iterator bereitgestellt werden kann oder nicht. Wenn Sie
Sequence
jedoch eine Iteration absichtlich auf eine einmalige Iteration beschränken möchten , können Sie dieconstrainOnce()
FunktionSequence
wie folgt verwenden:Erweiterte Funktionen
Sammle Beispiel 5 (ja, ich habe die bereits in der anderen Antwort übersprungen)
Nebenbei bemerkt können wir in Kotlin einfache Datenklassen erstellen und die Testdaten wie folgt instanziieren:
Sammeln Sie Beispiel 6
Ok, ein interessanter Fall hier für Kotlin. Zuerst die falschen Antworten, um Variationen beim Erstellen eines
Map
aus einer Sammlung / Sequenz zu untersuchen:Und jetzt zur richtigen Antwort:
Wir mussten nur die übereinstimmenden Werte verbinden, um die Listen zu reduzieren und einen Transformator bereitzustellen
jointToString
, um von derPerson
Instanz zur zu wechselnPerson.name
.Sammeln Sie Beispiel 7
Ok, dies kann leicht ohne einen Brauch gemacht werden
Collector
, also lasst es uns auf Kotlin-Weise lösen und dann ein neues Beispiel erfinden, das zeigt, wie ein ähnlicher Prozess durchgeführt wird, fürCollector.summarizingInt
den es in Kotlin nicht nativ gibt.Es ist nicht meine Schuld, dass sie ein triviales Beispiel ausgewählt haben !!! Ok, hier ist eine neue
summarizingInt
Methode für Kotlin und ein passendes Beispiel:SummarizingInt Beispiel
Es ist jedoch besser, eine Erweiterungsfunktion zu erstellen, 2 die tatsächlich zu den Stilen in Kotlin stdlib passt:
Jetzt haben Sie zwei Möglichkeiten, die neuen
summarizingInt
Funktionen zu verwenden:Und all dies führt zu den gleichen Ergebnissen. Wir können diese Erweiterung auch erstellen, um an
Sequence
und für geeignete primitive Typen zu arbeiten.Vergleichen Sie zum Spaß den Java JDK-Code mit dem benutzerdefinierten Kotlin-Code , der zum Implementieren dieser Zusammenfassung erforderlich ist.
quelle
.map { it.substring(1).toInt() }
: Wie Sie wissen, handelt es sich bei dem abgeleiteten Typ um einen Kotlin-Typ.In einigen Fällen ist es schwierig, Anrufe
collect(Collectors.toList())
oder ähnliches zu vermeiden . In diesen Fällen können Sie mithilfe von Erweiterungsfunktionen wie den folgenden schneller zu einem Kotlin-Äquivalent wechseln:Dann kannst du einfach
stream.toList()
oderstream.asSequence()
zurück in die Kotlin-API wechseln. Ein Fall wie z. B.Files.list(path)
zwingt Sie zu einem Fall , in demStream
Sie ihn möglicherweise nicht möchten, und diese Erweiterungen können Ihnen dabei helfen, wieder in die Standardsammlungen und die Kotlin-API zurückzukehren.quelle
Mehr zur Faulheit
Nehmen wir die von Jayson gegebene Beispiellösung für "Berechnung der Summe der Gehälter nach Abteilungen":
Um dies faul zu machen (dh zu vermeiden, dass im
groupBy
Schritt eine Zwischenkarte erstellt wird ), ist die Verwendung nicht möglichasSequence()
. Stattdessen müssen wir verwendengroupingBy
und bedienenfold
:Für manche Menschen ist dies möglicherweise sogar besser lesbar, da es sich nicht um Karteneinträge handelt: die
it.value
Teil der Lösung war zunächst auch für mich verwirrend.Da dies ein häufiger Fall ist und wir es vorziehen, nicht
fold
jedes Mal aufzuschreiben, ist es möglicherweise besser, nur eine generischesumBy
Funktion für Folgendes bereitzustellenGrouping
:damit wir einfach schreiben können:
quelle