En Java 8, il existe Stream.collect
ce qui permet des agrégations sur des collections. Dans Kotlin, cela n'existe pas de la même manière, à part peut-être comme une collection de fonctions d'extension dans la stdlib. Mais il n'est pas clair quelles sont les équivalences pour différents cas d'utilisation.
Par exemple, en haut du JavaDoc pour seCollectors
trouvent des exemples écrits pour Java 8, et lorsque vous les portez vers Kolin, vous ne pouvez pas utiliser les classes Java 8 lorsque vous utilisez une version JDK différente, ils devraient donc être écrits différemment.
En termes de ressources en ligne montrant des exemples de collections Kotlin, elles sont généralement triviales et ne se comparent pas vraiment aux mêmes cas d'utilisation. Quels sont les bons exemples qui correspondent vraiment aux cas tels que ceux documentés pour Java 8 Stream.collect
? La liste y est:
- Accumuler les noms dans une liste
- Accumuler les noms dans un TreeSet
- Convertir les éléments en chaînes et les concaténer, séparés par des virgules
- Calculer la somme des salaires de l'employé
- Regrouper les collaborateurs par département
- Calculer la somme des salaires par département
- Partitionner les élèves en réussissant et en échec
Avec des détails dans le JavaDoc lié ci-dessus.
Remarque: cette question est intentionnellement écrite et répondue par l'auteur ( Questions auto-répondues ), de sorte que les réponses idiomatiques aux sujets Kotlin les plus fréquemment posées soient présentes dans SO. Aussi pour clarifier certaines réponses vraiment anciennes écrites pour les alphas de Kotlin qui ne sont pas exactes pour Kotlin d'aujourd'hui.
la source
collect(Collectors.toList())
ou similaire, vous pouvez rencontrer ce problème: stackoverflow.com/a/35722167/3679676 (le problème, avec des solutions de contournement)Réponses:
Il existe des fonctions dans la bibliothèque standard de Kotlin pour la moyenne, le nombre, la distinction, le filtrage, la recherche, le regroupement, la jonction, le mappage, min, max, le partitionnement, le découpage, le tri, la sommation, vers / depuis des tableaux, vers / depuis des listes, vers / depuis des cartes , union, co-itération, tous les paradigmes fonctionnels, et plus encore. Vous pouvez donc les utiliser pour créer de petits 1-liners et il n'est pas nécessaire d'utiliser la syntaxe plus compliquée de Java 8.
Je pense que la seule chose qui manque dans laCollectors
classe Java 8 intégrée est la synthèse (mais dans une autre réponse à cette question est une solution simple) .Une chose qui manque dans les deux est le traitement par lots, qui est vu dans une autre réponse de Stack Overflow et a également une réponse simple. Un autre cas intéressant est celui de Stack Overflow: manière idiomatique de renverser la séquence en trois listes en utilisant Kotlin . Et si vous souhaitez créer quelque chose commeStream.collect
dans un autre but, consultez Stream.collect personnalisé dans KotlinEDIT 11.08.2017: Les opérations de collecte par blocs / fenêtres ont été ajoutées dans kotlin 1.2 M2, voir https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-2-m2-is-out/
Il est toujours bon d'explorer la référence API pour kotlin.collections dans son ensemble avant de créer de nouvelles fonctions qui pourraient déjà y exister.
Voici quelques conversions d'
Stream.collect
exemples Java 8 vers l'équivalent dans Kotlin:Accumuler les noms dans une liste
Convertir les éléments en chaînes et les concaténer, séparés par des virgules
Calculer la somme des salaires de l'employé
Regrouper les collaborateurs par département
Calculer la somme des salaires par département
Partitionner les élèves en réussissant et en échec
Noms des membres masculins
Grouper les noms des membres de la liste par sexe
Filtrer une liste vers une autre liste
Recherche de la chaîne la plus courte d'une liste
Comptage des éléments dans une liste après l'application du filtre
et ainsi de suite ... Dans tous les cas, aucune fonctionnalité spéciale de pliage, de réduction ou autre n'était requise pour imiter
Stream.collect
. Si vous avez d'autres cas d'utilisation, ajoutez-les dans les commentaires et nous pouvons voir!À propos de la paresse
Si vous souhaitez traiter paresseusement une chaîne, vous pouvez la convertir en
Sequence
utilisationasSequence()
avant la chaîne. À la fin de la chaîne de fonctions, vous vous retrouvez généralement avec unSequence
fichier. Ensuite , vous pouvez utilisertoList()
,toSet()
,toMap()
ou une autre fonction de matérialiser laSequence
fin.Pourquoi n'y a-t-il pas de types?!?
Vous remarquerez que les exemples Kotlin ne spécifient pas les types. En effet, Kotlin a une inférence de type complète et est complètement sûr au moment de la compilation. Plus que Java, car il a également des types nullables et peut aider à prévenir le redoutable NPE. Donc ceci à Kotlin:
est le même que:
Parce que Kotlin sait ce que
people
c'est, et quepeople.age
c'estInt
donc l'expression de filtre ne permet que la comparaison à unInt
, et c'estpeople.name
unString
donc l'map
étape produit unList<String>
(lecture seuleList
deString
).Maintenant, si
people
c'était possiblenull
, comme dans unList<People>?
alors:Renvoie un
List<String>?
qui devrait être vérifié par null ( ou utilisez l'un des autres opérateurs Kotlin pour les valeurs Nullable, voir cette manière idiomatique de Kotlin de traiter les valeurs Nullables et également la manière idiomatique de gérer une liste Nullable ou vide dans Kotlin )Voir également:
la source
Pour des exemples supplémentaires, voici tous les exemples de Java 8 Stream Tutorial convertis en Kotlin. Le titre de chaque exemple est dérivé de l'article source:
Comment fonctionnent les flux
Différents types de flux # 1
ou, créez une fonction d'extension sur String appelée ifPresent:
Voir aussi:
apply()
fonctionVoir aussi: Fonctions d'extension
Voir aussi:
?.
Opérateur Safe Call , et en général nullabilité: dans Kotlin, quelle est la manière idiomatique de traiter les valeurs nullables, de les référencer ou de les convertirDifférents types de flux # 2
Différents types de flux # 3
Différents types de flux # 4
Différents types de flux # 5
Différents types de flux # 6
Différents types de flux # 7
Pourquoi la commande est importante
Cette section du didacticiel Java 8 Stream est la même pour Kotlin et Java.
Réutilisation des flux
Dans Kotlin, cela dépend du type de collection si elle peut être consommée plus d'une fois. A
Sequence
génère un nouvel itérateur à chaque fois, et à moins qu'il n'affirme "utiliser une seule fois", il peut se réinitialiser au début chaque fois qu'il est actionné. Par conséquent, alors que ce qui suit échoue dans le flux Java 8, mais fonctionne dans Kotlin:Et en Java pour obtenir le même comportement:
Par conséquent, dans Kotlin, le fournisseur des données décide s'il peut se réinitialiser et fournir un nouvel itérateur ou non. Mais si vous souhaitez contraindre intentionnellement une
Sequence
itération à une fois, vous pouvez utiliser laconstrainOnce()
fonctionSequence
comme suit:Opérations avancées
Collectez l'exemple n ° 5 (oui, j'ai sauté ceux déjà dans l'autre réponse)
Et en remarque, dans Kotlin, nous pouvons créer des classes de données simples et instancier les données de test comme suit:
Collectez l'exemple n ° 6
Ok, un cas plus intéressant ici pour Kotlin. D'abord les mauvaises réponses pour explorer les variantes de création d'un à
Map
partir d'une collection / séquence:Et maintenant pour la bonne réponse:
Nous avions juste besoin de joindre les valeurs correspondantes pour réduire les listes et fournir un transformateur
jointToString
pour passer de l'Person
instance auPerson.name
.Collectez l'exemple n ° 7
Ok, celui-ci peut facilement être fait sans coutume
Collector
, donc résolvons-le à la manière de Kotlin, puis inventons un nouvel exemple qui montre comment faire un processus similaire pourCollector.summarizingInt
lequel n'existe pas nativement dans Kotlin.Ce n'est pas ma faute, ils ont choisi un exemple trivial !!! Ok, voici une nouvelle
summarizingInt
méthode pour Kotlin et un échantillon correspondant:Exemple SummarizingInt
Mais il est préférable de créer une fonction d'extension, 2 pour faire correspondre les styles dans Kotlin stdlib:
Vous avez maintenant deux façons d'utiliser les nouvelles
summarizingInt
fonctions:Et tout cela produit les mêmes résultats. Nous pouvons également créer cette extension pour travailler sur
Sequence
et pour les types primitifs appropriés.Pour le plaisir, comparez le code Java JDK au code personnalisé Kotlin requis pour implémenter cette synthèse.
la source
.map { it.substring(1).toInt() }
: comme vous le savez bien, le type inféré est celui de la puissance kotlin.Il y a des cas où il est difficile d'éviter d'appeler
collect(Collectors.toList())
ou similaire. Dans ces cas, vous pouvez passer plus rapidement à un équivalent Kotlin en utilisant des fonctions d'extension telles que:Ensuite, vous pouvez simplement
stream.toList()
oustream.asSequence()
revenir à l'API Kotlin. Un cas tel queFiles.list(path)
vous oblige àStream
ne pas le vouloir, et ces extensions peuvent vous aider à revenir aux collections standard et à l'API Kotlin.la source
En savoir plus sur la paresse
Prenons l'exemple de solution pour "Calculer la somme des salaires par département" donnée par Jayson:
Afin de rendre cela paresseux (c'est-à-dire éviter de créer une carte intermédiaire dans l'
groupBy
étape), il n'est pas possible d'utiliserasSequence()
. Au lieu de cela, nous devons utilisergroupingBy
etfold
opération:Pour certaines personnes, cela peut même être plus lisible, puisque vous n'avez pas affaire à des entrées de carte: la
it.value
partie de la solution était déroutante pour moi aussi au début.Comme il s'agit d'un cas courant et que nous préférerions ne pas l'écrire à
fold
chaque fois, il peut être préférable de simplement fournir unesumBy
fonction générique surGrouping
:afin que nous puissions simplement écrire:
la source