当前位置: 首页 > 知识库问答 >
问题:

使用自定义收集器对象对Java流中哈希映射中的值进行分组?

花健
2023-03-14

Java流新手在这里。目前我正在完成本书中关于收集者的第6章(用流收集数据)。

我的对象是这样的。

    public class Report {

    private String movie;
    private int movieId;
    private int projections;
    private int tickets;
    private double income;
}

这样做的目的是得到某种总体总结报告。基本上是一个HashMap

关键1:

投影-表示每个报告中所有投影的总和。

关键2:

<代码>票据-表示每个报表中所有票据的总和。

关键3:

收入-表示每个报表的所有收入之和。

现在,我实际上通过创建自定义收集器来进行赋值,称为MapCollector

    public class MapCollector implements Collector<Report, Map<String, Double>, Map<String, Double>>{

    @SuppressWarnings("serial")
    @Override
    public Supplier<Map<String, Double>> supplier() {

        return () ->  new HashMap<String, Double>() {{
            put("projections", 0.0);
            put("tickets", 0.0);
            put("income", 0.0);
        }};
    }

    @Override
    public BiConsumer<Map<String, Double>, Report> accumulator() {

        return (map, report) -> 
        {
            map.put("projections", map.get("projections") + report.getProjections());
            map.put("tickets", map.get("tickets") + report.getTickets());
            map.put("income", map.get("income") + report.getIncome());          
        };
    }

    @Override
    public BinaryOperator<Map<String, Double>> combiner() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Function<Map<String, Double>, Map<String, Double>> finisher() {
        // TODO Auto-generated method stub
        return Function.identity();
    }

    @Override
    public Set<Characteristics> characteristics() {
        // TODO Auto-generated method stub
        return Collections.unmodifiableSet(EnumSet.of(
                IDENTITY_FINISH, CONCURRENT));
    }
}

所以我得到的结果是这样的:

HashMap<String, Double> result = (HashMap<String, Double>) reports.stream().collect(new MapCollector());

所以,我的问题是,为什么不创建新的收集器对象而以不同的方式执行此操作?也许,可以通过某种方式使用分组方式,或者使用减少?或者其他(更好)更可读的方式?

共有1个答案

韦翰音
2023-03-14

实际上,您不需要自定义收集器来实现此目的。您只需要供应商、累加器和合路器。

您可以将它们与流放在同一个类中,并按如下方式调用它:

HashMap<String, Double> result = (HashMap<String, Double>) 
                                 reports.stream()
                                        .collect(
                                          this::supplier,
                                          this::acumulator,
                                          this::combiner);

其中方法如下所示:

private Map<String, Double> supplier() {
    return new HashMap<String, Double>() {{
        put("projections", 0.0);
        put("tickets", 0.0);
        put("income", 0.0);
    }};
}

private void accumulator(Map<String, Double> map, Report report) {
    map.merge("projections", report.getProjections(), Double::sum);
    map.merge("tickets", report.getTickets(), Double::sum);
    map.merge("income", report.getIncome(), Double::sum);
}

private void combiner(Map<String, Double> firstMap, Map<String, Double> secondMap) {
    secondMap.forEach((k, v) -> firstMap.merge(k, v, Double::sum));
}
 类似资料:
  • 问题内容: 使用hashmap而不是使用对象类好吗……使用Hashmap…。 并使用对象类..... 请在应用程序运行状况,内存要求等方面告诉我… 问题答案: 这在很大程度上取决于您要实现的目标:为了提高灵活性,哈希映射会更好。但是灵活性是有代价的:哈希映射比具有相同数量的强类型字段的类还要大和慢。 哈希映射比具有相同数量字段的类具有更大的内存占用量 哈希图会强制对基元进行装箱 哈希图的创建和访问

  • 我有一个用例,其中我需要维护两组JSON输出,一组具有JSON属性的漂亮名称,另一组没有。所以我决定自定义ObjectMapper,以便它忽略字段上的@JSONProperty(“pretty name”)注释,而使用字段属性名。在本例中,希望得到以下JSON输出 具有漂亮名称的JSON输出如下所示 我的ObjectMapper配置代码如下所示 我看了一些其他的答案,但对我不起作用。我得到了一个N

  • 问题内容: 我有以下课程。 我希望能够按年龄分组,然后收集人员名称列表,而不是人员对象本身。全部以一个漂亮的lamba表达式表示。 为了简化所有步骤,我链接了当前的解决方案,该解决方案按年龄存储分组的结果,然后对其进行迭代以收集名称。 当前解决方案 不理想,为了学习,我想有一个更优雅,更有效的解决方案。 问题答案: 将Stream与分组时,可以使用自定义对值指定归约运算。在这里,我们需要使用,它需

  • 我有一个地图列表,并希望对某些列进行分组和求和。 地图列表:

  • 我在glassfish服务器上使用Jersey的最新版本(2.13),以及jackson的最新版本(版本.2.4)。我已经编写并注册了一个自定义ObjectMapper,但它似乎只有集合被我的自定义ObjectMapper序列化。 我在这个页面上看到了类似的问题:https://java.net/jira/browse/glassfish-20815,但是这里提供的解决方案对我不起作用。