You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用flatMap流式声明式写法替代foreach生成指定结构HashMap

用Java流式API实现嵌套集合的分组与KPI合并去重

核心实现(Java 9+)

利用flatMap层层展开嵌套集合,结合Collectors.groupingBy和Collectors.flatMapping实现需求,代码更简洁且符合声明式风格:

import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

private Map<String, List<String>> getViewKpis(List<Role> roles) {
    return roles.stream()
            // 展开所有角色包含的视图
            .flatMap(role -> role.getViews().stream())
            // 将每个视图与子视图配对,生成「键-KPI列表」的条目
            .flatMap(view -> view.getSubViews().stream()
                    .map(subView -> new AbstractMap.SimpleEntry<>(
                            String.join("|", view.getViewName(), subView.getSubViewName()),
                            subView.getKpis())))
            // 按键分组,合并所有KPI并去重
            .collect(Collectors.groupingBy(
                    AbstractMap.SimpleEntry::getKey,
                    Collectors.flatMapping(
                            entry -> entry.getValue().stream(),
                            Collectors.collectingAndThen(
                                    Collectors.toList(),
                                    kpis -> kpis.stream().distinct().collect(Collectors.toList())
                            )
                    )
            ));
}

可读性优化版本(Java 16+)

使用Java 16引入的record定义简单数据容器,替代AbstractMap.SimpleEntry,代码可读性更强:

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

// 定义键与KPI列表的配对记录
private record KeyKpiPair(String key, List<String> kpis) {}

private Map<String, List<String>> getViewKpis(List<Role> roles) {
    return roles.stream()
            .flatMap(role -> role.getViews().stream())
            .flatMap(view -> view.getSubViews().stream()
                    .map(subView -> new KeyKpiPair(
                            String.join("|", view.getViewName(), subView.getSubViewName()),
                            subView.getKpis())))
            .collect(Collectors.groupingBy(
                    KeyKpiPair::key,
                    Collectors.flatMapping(
                            pair -> pair.kpis().stream(),
                            Collectors.collectingAndThen(
                                    Collectors.toList(),
                                    kpis -> kpis.stream().distinct().collect(Collectors.toList())
                            )
                    )
            ));
}

Java 8兼容版本

由于Java 8没有Collectors.flatMapping,需要分两步处理:先分组得到嵌套列表,再展开去重:

import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

private Map<String, List<String>> getViewKpis(List<Role> roles) {
    // 第一步:按键分组,得到键对应多个KPI列表的嵌套结构
    Map<String, List<List<String>>> grouped = roles.stream()
            .flatMap(role -> role.getViews().stream())
            .flatMap(view -> view.getSubViews().stream()
                    .map(subView -> new AbstractMap.SimpleEntry<>(
                            String.join("|", view.getViewName(), subView.getSubViewName()),
                            subView.getKpis())))
            .collect(Collectors.groupingBy(
                    AbstractMap.SimpleEntry::getKey,
                    Collectors.mapping(AbstractMap.SimpleEntry::getValue, Collectors.toList())
            ));

    // 第二步:展开嵌套列表,去重后生成最终Map
    return grouped.entrySet().stream()
            .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    entry -> entry.getValue().stream()
                            .flatMap(List::stream)
                            .distinct()
                            .collect(Collectors.toList())
            ));
}

代码逻辑说明

  1. 展开嵌套集合:通过两次flatMap,依次将Role→View→SubView的嵌套结构展开为扁平的条目流;
  2. 生成分组键:为每个SubView生成viewName|subViewName格式的键,并关联对应的KPI列表;
  3. 分组与合并去重:通过分组收集所有对应键的KPI,再展开并去重,得到与原foreach实现完全一致的结果。

内容的提问来源于stack exchange,提问作者Moussa ELaQ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 01:48:38