Confondu par Java8 Collectionneurs.toMap
J'ai une collection qui ressemble à ci-dessous, et je veux filtrer le tout, sauf les dates qui ne sont pas à la fin du mois.
2010-01-01=2100.00,
2010-01-31=2108.74,
2010-02-01=2208.74,
2010-02-28=2217.92,
2010-03-01=2317.92,
2010-03-31=2327.57,
2010-04-01=2427.57,
2010-04-30=2437.67,
2010-05-01=2537.67,
2010-05-31=2548.22,
2010-06-01=2648.22,
2010-06-30=2659.24,
2010-07-01=2759.24,
2010-07-31=2770.72,
2010-08-01=2870.72,
2010-08-31=2882.66,
2010-09-01=2982.66,
2010-09-30=2995.07,
2010-10-01=3095.07,
2010-10-31=3107.94,
2010-11-01=3207.94,
2010-11-30=3221.29
J'ai le texte suivant des critères de filtre. frequency.getEnd
renvoie une LocalDate
correspondant à la fin du mois pour le LocalDate
.
.filter(p -> frequency.getEnd(p.getKey()) == p.getKey())
Alors maintenant, je pense que je convertis cette filtré flux de retour pour une carte. Et je pense utiliser un collecteur de le faire. J'ai donc ajouter:
.collect(Collectors.toMap(/* HUH? */));
Mais je ne sais pas quoi faire avec Collectors.toMap
. La lecture des exemples qui me laisse confus. Voici mon code actuel qui, évidemment, ne fonctionne pas.
TreeMap<LocalDate, BigDecimal> values = values.entrySet()
.stream()
.filter(p -> frequency.getEnd(p.getKey()) == p.getKey())
.collect(Collectors.toMap(/* HUH? */));
OriginalL'auteur Patrick | 2015-11-15
Vous devez vous connecter pour publier un commentaire.
En plus de la réponse à la question précédente note que si vous n'avez pas besoin de garder l'original de la carte, vous pouvez effectuer ce filtrage en place sans l'aide de l'API Stream:
OriginalL'auteur Tagir Valeev
Considérez votre problème comme ceci: vous avez un Flux d'entrée d'une carte, c'est-à-dire un
Stream<Map.Entry<LocalDate, BigDecimal>>
, et que vous souhaitez collecter dans unTreeMap<LocalDate, BigDecimal>
.Donc, vous êtes de droite, vous devez utiliser
Collectors.toMap
. Maintenant, comme vous pouvez le voir dans la documentation, il y a en fait 3Collectors.toMap
, selon les arguments:toMap(keyMapper, valueMapper)
.keyMapper
est une fonction dont l'entrée est le flux de l'élément actuel et dont la production est la clé de la Carte finale. Ainsi, il cartes le Flux de l'élément à clé (d'où le nom).valueMapper
est une fonction dont l'entrée est le flux de l'élément actuel et dont la sortie est la valeur de la Carte finale.toMap(keyMapper, valueMapper, mergeFunction)
. Les deux premiers paramètres sont les mêmes qu'avant. La troisième,mergeFunction
, est une fonction qui est appelée en cas de doublon éléments clés dans la Carte finale; par conséquent, ses entrées sont 2 valeurs (c'est à dire les deux valeurs pour lesquelleskeyMapper
retourné la même clé) et fusionne les deux valeurs en un seul.toMap(keyMapper, valueMapper, mergeFunction, mapSupplier)
. Les trois premiers arguments sont les mêmes qu'avant. Le quatrième est un fournisseur de Carte: comme c'est actuellement mis en œuvre dans le JDK, les deux précédentstoMap
retour d'unHashMap
instance. Mais si vous voulez une Carte spécifique à l'instance, le fournisseur sera de retour cette instance.Dans notre cas précis, nous avons besoin d'utiliser la troisième
toMap
, parce que nous voulons que le résultat de la Carte à explicitement unTreeMap
. Voyons ce que nous avons doit donner:keyMapper
: donc, cela devrait revenir sur la touche de la Carte finale. Ici, nous avons affaire à unStream<Map.Entry<LocalDate, BigDecimal>>
de sorte que chaque Flux de l'élément est de typeMap.Entry<LocalDate, BigDecimal>
. Cette fonction prend alors unMap.Entry<LocalDate, BigDecimal> e
comme entrée. Sa sortie devrait être la clé de la Carte finale, dans ce cas, la sortie doit êtree.getKey()
, c'est à dire laLocalDate
que l'entrée est maintenant. Cela peut être écrite comme une expression lambda:e -> e.getKey()
. Cela pourrait aussi être écrit comme une méthode de référenceMap.Entry::getKey
mais tenons-nous en à lambdas ici, parce qu'il pourrait être plus facile à comprendre.valueMapper
: c'est le même que ci-dessus, mais, dans ce cas, cette fonction doit retournere.getValue()
, c'est à dire laBigDecimal
que l'entrée est maintenant. C'est donce -> e.getValue()
.mergeFunction
: c'est une question délicate. Nous savons qu'il n'y a pas de clé en double éléments (c'est à dire pas de duplicateLocalDate
) dans la Carte finale, par construction. Que faisons-nous écrire ici? Une solution simple est de lancer une exception: il ne doit pas se produire et s'il le fait, il y a un gros problème quelque part. Donc, tout ce que les deux arguments d'entrée, nous allons lancer une exception. Cela peut être écrite comme(v1, v2) -> { throw new SomeException(); }
. Notez qu'il doit être mis entre parenthèses. Dans ce cas, et pour être cohérent avec ce que le JDK actuellement, j'ai choisiSomeException
êtreIllegalStateException
.mapSupplier
: comme dit précédemment, nous voulons fournir unTreeMap
. Un fournisseur ne prend aucun argument et retourne une nouvelle instance. Donc cela peut être écrite comme() -> new TreeMap<>()
ici. Encore une fois, nous pourrions utiliser une méthode de référence et d'écrireTreeMap::new
.Code Final, j'ai simplement écrit la collecte d'une partie du Flux (à noter que dans ce code, vous pouvez également utiliser la méthode correspondante-références, comme dit plus haut, j'ai ajouté ici dans les commentaires):
Et bien j'ai essayé d'être aussi explicite que je le pouvais. L'OP est confus au sujet de collectionneurs en général (et peut-être que les lambdas en général) donc je pense que prendre le temps d'expliquer, c'est une bonne chose. Je suis d'accord qu'il y a tout un tas de parler pour 6 lignes de code à la fin, mais je pense que c'est nécessaire.
Merci pour beaucoup de détails. Je pense que j'aurais été perdu sur le mergeFunction (parce que je ne suis pas la fusion de quoi que ce soit), et le mapSupplier. Je me suis retrouvé avec quelques petits mods que j'ai ajouté en bas de mon post.
Ne pas ajouter votre code final à la fin de votre post, cela casse le Q&Un format de. En acceptant cette réponse, vous avez déjà dit au futur lecteur que vous avez pensé que c'était la meilleure réponse. Je l'ai enlevé.
oui, je suis nouveau sur le flux de l'api ainsi que des collectionneurs donc je n'ai pas tout intériorisé. Votre verbose description était exactement ce dont j'avais besoin car mon but est d'apprendre plutôt que de demander le code et de progresser. Merci encore.
OriginalL'auteur Tunaki
Puisque vous êtes itération
Map.Entry
valeurs, ettoMap()
juste besoin de deux méthodes d'extraction de la clé et de la valeur, c'est simple:Noter que ce sera pas retour d'un
TreeMap
. Pour cela, vous devez:OriginalL'auteur Andreas
La toMap méthode dans sa forme la plus simple qui prend deux arguments: l'un est une fonction de la carte d'entrée à la clé, et de l'autre une fonction de carte à l'entrée de la valeur. La sortie de ces deux fonctions sont combinées pour former une entrée dans la carte.
Je pense que vous avez besoin de faire quelque chose comme ceci:
TreeMap
de sortie, pas le courant de défautHashMap
.Je ne vois pas spécifiquement qu'il veut un TreeMap. Il montre un exemple qui est à l'aide d'un TreeMap, ce qui n'est pas une obligation.
OriginalL'auteur Tom