自定义地图收集器

时间:2017-01-03 14:40:25

标签: java dictionary java-8 java-stream collectors

我有一个<script type="application/ld+json"> { "@context": "http://schema.org", "@type": "Organization", "url": "http://www.example.com/", "contactPoint": [{ "@type": "ContactPoint", "telephone": "+1-401-555-1212", "contactType": "customer service" }] } </script> 的集合,以前是使用流分组的。 Map<Pair<DateTime, String>, List<Entity>>是一个包含Entity属性和int方法的简单类。

现在,我希望将getValue()的值与我的简单Entity的用法进行汇总,将前一张地图的类型设置为EntityAccumulator。根据我的理解,实现这一目标的唯一方法是创建我自己的自定义收藏家,但我仍然坚持Map<Pair<DateTime, String>, EntityAccumulator>方法应该返回finisher()

或者,也许有更简单的方法来实现我想要的结果?

StreamProcessing

Pair

EntityAccumulator

 Map<Pair<DateTime, String>, EntityAccumulator> collect = entities.stream()
                .collect(Collectors.groupingBy(entity-> Pair.of(entity.getTimestamp(), entity.getName())))
                .entrySet().stream()
                .collect(new EntityCollector()));

集电极

private static class EntityAccumulator {

        private int result = 0.0;

        public EntityAccumulator() { }

        public EntityAccumulator(int result) {
            this.result = result;
        }

        public void calculate(Entity entity) {
            result += entity.getValue();
        }

        public EntityAccumulatoradd(EntityAccumulator other) {
            return new EntityAccumulator(this.result + other.result);
        }
}

1 个答案:

答案 0 :(得分:5)

显然,你真的想做

Map<Pair<DateTime, String>, Double> collect = entities.stream()
    .collect(Collectors.groupingBy(
        entity -> Pair.of(entity.getTimestamp(), entity.getName()),
        Collectors.summingDouble(Entity::getValue)));

Map<Pair<DateTime, String>, Integer> collect = entities.stream()
    .collect(Collectors.groupingBy(
        entity -> Pair.of(entity.getTimestamp(), entity.getName()),
        Collectors.summingInt(Entity::getValue)));

取决于实际值类型。您的声明int result = 0.0不太清楚。

首先,如果要对组执行缩减,则应将值Collector作为groupingBy collector的第二个参数提供。然后,它不必同时处理MapMap.Entry

由于它基本上将实体折叠为单个数字(对于每个组),因此您可以使用现有的收集器,即summingIntsummingDouble

创建自己的收集器时,无法在已在累加器功能中删除的装订器功能中重建信息。如果您的容器类型EntityAccumulator仅包含一个数字,则无法从中生成Map.Entry<Pair<DateTime, String>, EntityAccumulator>

顺便说一下,即使在创建自定义收集器时,也很少需要使用类实现Collector接口。您只需使用Collector.of,指定功能和特征,即可创建Collector

因此,使用原来的EntityAccumulator课程(假设result应为int0.0是拼写错误),您可以使用

Map<Pair<DateTime, String>, Integer> collect = entities.stream()
    .collect(Collectors.groupingBy(
        entity -> Pair.of(entity.getTimestamp(), entity.getName()),
        Collector.of(EntityAccumulator::new,
                     EntityAccumulator::calculate,
                     EntityAccumulator::add,
                     ea -> ea.result,
                     Collector.Characteristics.UNORDERED)));

实现与上述相同。也可以通过两个步骤执行操作,例如尝试使用

Map<Pair<DateTime, String>, Integer> collect = entities.stream()
    .collect(Collectors.groupingBy(e -> Pair.of(e.getTimestamp(), e.getName())))
    .entrySet().stream()
    .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().stream().collect(
        Collector.of(EntityAccumulator::new,
                     EntityAccumulator::calculate,
                     EntityAccumulator::add,
                     ea -> ea.result,
                     Collector.Characteristics.UNORDERED))));

但是,当然,这只是为了完整性。本答案开头显示的解决方案更简单,更有效。