La plupart du temps, lorsque vous vous retrouvez à utiliser forEach
sur un Stream, vous devriez réfléchir à savoir si vous utilisez le bon outil pour votre tâche ou si vous l'utilisez de la bonne manière.
En général, vous devriez rechercher une opération terminale appropriée faisant ce que vous souhaitez accomplir ou un collecteur approprié. Maintenant, il existe des collecteurs pour produire des Map
s et des List
s, mais aucun collecteur prêt à l'emploi pour combiner deux collecteurs différents, basés sur un prédicat.
Maintenant, cette réponse contient un collecteur pour combiner deux collecteurs. En utilisant ce collecteur, vous pouvez accomplir la tâche comme suit
Pair, List> pair = animalMap.entrySet().stream()
.collect(conditional(entry -> entry.getValue() != null,
Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue),
Collectors.mapping(Map.Entry::getKey, Collectors.toList()) ));
Map myMap = pair.a;
List myList = pair.b;
Mais peut-être que vous pouvez résoudre cette tâche spécifique de manière plus simple. Un de vos résultats correspond au type d'entrée; c'est la même map juste dépouillée des entrées qui se rapportent à null
. Si votre map d'origine est mutable et que vous n'en avez plus besoin par la suite, vous pouvez simplement collecter la liste et supprimer ces clés de la map d'origine car elles sont mutuellement exclusives :
List myList=animalMap.entrySet().stream()
.filter(pair -> pair.getValue() == null)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
animalMap.keySet().removeAll(myList);
Notez que vous pouvez supprimer les mappings vers null
même sans avoir la liste des autres clés :
animalMap.values().removeIf(Objects::isNull);
ou
animalMap.values().removeAll(Collections.singleton(null));
Si vous ne pouvez pas (ou ne souhaitez pas) modifier la map d'origine, il existe encore une solution sans collecteur personnalisé. Comme suggéré dans la réponse de Alexis C., partitioningBy
va dans la bonne direction, mais vous pouvez simplifier cela :
Map> tmp = animalMap.entrySet().stream()
.collect(Collectors.partitioningBy(pair -> pair.getValue() != null,
Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
Map myMap = tmp.get(true);
List myList = new ArrayList<>(tmp.get(false).keySet());
En fin de compte, n'oubliez pas les opérations ordinaires sur les Collections, vous n'avez pas besoin de tout faire avec la nouvelle API Stream.
3 votes
On dirait une situation où les flux ne vous aident pas vraiment. Cela cache simplement la syntaxe du flux de contrôle avec une API de manière maladroite et votre lambda
forEach
est étatique.