在大多数情况下,当您发现自己在Stream上使用时,您应该重新考虑是否正在为您的工作使用正确的工具,或者您是否以正确的方式使用它。forEach
通常,您应该寻找适当的终端操作来执行您想要实现的目标或适当的收集器。现在,有用于生产 s 和 s 的收集器,但没有用于基于谓词组合两个不同收集器的现成收集器。Map
List
现在,此答案包含一个用于组合两个收集器的收集器。使用此收集器,您可以通过以下方式完成任务:
Pair<Map<KeyType, Animal>, List<KeyType>> 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<KeyType,Animal> myMap = pair.a;
List<KeyType> myList = pair.b;
但也许,你可以用更简单的方式解决这个特定的任务。其中一个结果与输入类型匹配;这是相同的地图,只是剥离了映射到的条目。如果您的原始地图是可变的,并且您之后不需要它,则只需收集列表并从原始地图中删除这些键,因为它们是互斥的:null
List<KeyType> myList=animalMap.entrySet().stream()
.filter(pair -> pair.getValue() == null)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
animalMap.keySet().removeAll(myList);
请注意,即使没有其他键的列表,您也可以删除映射到:null
animalMap.values().removeIf(Objects::isNull);
或
animalMap.values().removeAll(Collections.singleton(null));
如果您不能(或不想)修改原始地图,则仍有一个没有自定义收集器的解决方案。正如Alexis C.的答案所暗示的那样,正朝着正确的方向前进,但你可以简化它:partitioningBy
Map<Boolean,Map<KeyType,Animal>> tmp = animalMap.entrySet().stream()
.collect(Collectors.partitioningBy(pair -> pair.getValue() != null,
Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
Map<KeyType,Animal> myMap = tmp.get(true);
List<KeyType> myList = new ArrayList<>(tmp.get(false).keySet());
最重要的是,不要忘记普通的收集操作,您不必使用新的流API执行所有操作。