【问题标题】:How to create list of object instead of map with groupingBy collector?如何使用 groupingBy 收集器创建对象列表而不是地图?
【发布时间】:2021-06-22 23:11:16
【问题描述】:

我有以下流操作。

Map<String, Integer> pieDataMap = expenses.stream()
    .collect(groupingBy(expense -> typeClassifier.apply(expense, chartCriteria), 
                        summingInt(Expense::getCost)));

我想获取类型为PieEntry 的对象列表,而不是获取Map&lt;String, Integer&gt;,它有两个arg 构造函数PieEntry(String, Integer)。简而言之,我想将 map 的每个条目( 类型)转换为 PieEntry 类的对象(带有两个参数构造函数)并将结果对象收集为列表。

如何在不迭代结果地图并在额外循环中创建对象的情况下做到这一点?

【问题讨论】:

标签: java java-8 java-stream


【解决方案1】:

根据groupingBy函数签名,

static <T,K,A,D> Collector<T,?,Map<K,D>>    groupingBy(Function<? super T,? extends K> classifier, Collector<? super T,A,D> downstream)

它返回一个收集器,该收集器生成(将元素收集到)地图,并且由于此操作是终端操作,因此无法再在同一语句中处理生成的地图。

【讨论】:

    【解决方案2】:

    如果问题是是否可以使用原始流而不分组到地图来完成,那么这是不可能的。要对结果进行分组,需要处理整个输入,因为无法知道下游是否会有新元素最终进入其中一个组。

    所以你必须得到一个分组映射,然后将其条目映射到PieEntry 对象:

    pieDataMap.stream().entrySet().stream().map(entry -> new PieEntry(entry.getKey(), entry.getValue()));
    

    您也可以在.collect()之后将其链接到原始流链。

    【讨论】:

    • 您能否详细说明“...需要处理整个输入,因为无法知道下游是否会有新元素最终进入其中一个组。” ?
    • 流背后的想法是,可以一次性处理同一流上的所有操作(过滤、映射、跳过等),而无需一遍又一遍地遍历输入。在使用终端操作之前,流保持未处理状态,例如.collect().min().max().count() 等。更多阅读:docs.oracle.com/javase/8/docs/api/java/util/stream/…。在您的情况下,为了从 expenses 输入构建组,应遍历此输入中的所有项目。否则无法知道每个组的最终成本。
    猜你喜欢
    • 1970-01-01
    • 2016-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 1970-01-01
    • 2020-04-12
    • 1970-01-01
    相关资源
    最近更新 更多