如何在 Java 8 流 forEach 中使用 if-else 逻辑

2022-08-31 14:44:16

我想做的是下面2个流调用。我想根据某种情况将一个集合拆分为 2 个新集合。理想情况下,我想在1中完成。我已经看到了用于流的.map功能的条件,但找不到forEach的任何内容。实现我想要的目标的最佳方式是什么?

    animalMap.entrySet().stream()
            .filter(pair-> pair.getValue() != null)
            .forEach(pair-> myMap.put(pair.getKey(), pair.getValue()));

    animalMap.entrySet().stream()
            .filter(pair-> pair.getValue() == null)
            .forEach(pair-> myList.add(pair.getKey()));

答案 1

只需将条件放入 lambda 本身,例如

animalMap.entrySet().stream()
        .forEach(
                pair -> {
                    if (pair.getValue() != null) {
                        myMap.put(pair.getKey(), pair.getValue());
                    } else {
                        myList.add(pair.getKey());
                    }
                }
        );

当然,这假设集合 ( 和 ) 都是在上述代码段之前声明和初始化的。myMapmyList


更新:使用使代码更短,更高效,可读性更高,正如Jorn Vernee所建议的那样:Map.forEach

    animalMap.forEach(
            (key, value) -> {
                if (value != null) {
                    myMap.put(key, value);
                } else {
                    myList.add(key);
                }
            }
    );

答案 2

在大多数情况下,当您发现自己在Stream上使用时,您应该重新考虑是否正在为您的工作使用正确的工具,或者您是否以正确的方式使用它。forEach

通常,您应该寻找适当的终端操作来执行您想要实现的目标或适当的收集器。现在,有用于生产 s 和 s 的收集器,但没有用于基于谓词组合两个不同收集器的现成收集器。MapList

现在,此答案包含一个用于组合两个收集器的收集器。使用此收集器,您可以通过以下方式完成任务:

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执行所有操作。


推荐