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

新手上路,请多包涵

我想要做的在下面的 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()));

原文由 user3768533 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

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

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

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


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

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

原文由 Alex Shesterov 发布,翻译遵循 CC BY-SA 3.0 许可协议

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

通常,您应该寻找一个合适的终端操作来完成您想要实现的目标,或者寻找一个合适的收集器。现在,有用于生成 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());

底线是,不要忘记普通的 Collection 操作,您不必使用新的 Stream API 做所有事情。

原文由 Holger 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏