繁体   English   中英

Java 8 Collector.groupingBy下游的分类器值

[英]Java 8 Collector.groupingBy classifier value in downstream

在以下示例中,将分类器值提供给收集器的供应商功能的正确方法是什么:

import static java.math.BigDecimal.*;
import static java.util.stream.Collector.*;
import static java.util.stream.Collectors.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Test {

    public static class Item {
        String key;
        BigDecimal a;
        BigDecimal b;
        public Item(String key, BigDecimal a, BigDecimal b) {
            this.key = key;
            this.a = a;
            this.b = b;
        }
        public String getKey() {
            return key;
        }
        public BigDecimal getA() {
            return a;
        }
        public BigDecimal getB() {
            return b;
        }


    }
    public static class ItemSum {
        public ItemSum() {
        }

        public ItemSum(String key) {
            this.key = key;
        }
        String key;
        BigDecimal sumA = ZERO;
        BigDecimal sumB = ZERO;
        public void add(BigDecimal a, BigDecimal b) {
            sumA = sumA.add(a);
            sumB = sumB.add(b);
        }

        public ItemSum merge(ItemSum is) {
            sumA = sumA.add(is.getSumA());
            sumB = sumB.add(is.getSumB());
            return this;
        }
        public BigDecimal getSumA() {
            return sumA;
        }
        public BigDecimal getSumB() {
            return sumB;
        }


    }

    public static void main(String[] args) {

        Map<String, ItemSum> map = list().stream().collect(
                groupingBy(Item::getKey, 
                        of(
                                ItemSum::new, 
                                (s,i) -> {s.add(i.getA(), i.getB());},
                                (i,j) -> {return i.merge(j);}
                                )
                        )
                );
        map.forEach((k,v) -> {System.out.println(String.format("%s: A: %s: B: %s", k, v.getSumA(), v.getSumB()));});
    }

    public static List<Item> list() {
        List<Item> list = new ArrayList<>(3);
        list.add(new Item("a", ONE, ONE));
        list.add(new Item("a", ONE, ONE));
        list.add(new Item("b", ONE, ONE));
        return list;
    }

}

问题是在构建期间将键值传递给ItemSum 之后我有一些解决方法来填充关键字段,但我想知道是否有办法在供应商中执行此操作并消除ItemSum的默认构造函数

这是toMap(keyMapper, valueMapper, mergeFunction)收集器的作业,而不是groupingBy收集器。

让我们添加一个构造函数

public ItemSum(Item item) {
    this.key = item.getKey();
    this.sumA = item.getA();
    this.sumB = item.getB();
}

ItemSum类。 此构造函数基于Item初始化一个ItemSum 然后,您可以删除默认构造函数(不需要它)。 然后你可以简单地拥有以下内容:

Map<String, ItemSum> map = 
    list().stream()
          .collect(Collectors.toMap(Item::getKey, ItemSum::new, ItemSum::merge));

这样做是将每个Item元素收集到按每个Item的键分类的地图中。 对于该值,我们使用单个ItemSum对其进行初始化。 当遇到同一个键的多个值时,我们将它们合并在一起。

简而言之,你不能按照你想要的方式去做。

如果让ItemSum类在add方法(收集器的累加器方法)中接收Item实例,则可以轻松实现所需:

public class ItemSum {

    String key;

    BigDecimal sumA = ZERO;

    BigDecimal sumB = ZERO;

    public void add(Item item) {
        key = item.getKey();
        sumA = sumA.add(item.getA());
        sumB = sumB.add(item.getB());
    }

    public ItemSum merge(ItemSum is) {
        sumA = sumA.add(is.getSumA());
        sumB = sumB.add(is.getSumB());
        return this;
    }

    public BigDecimal getSumA() {
        return sumA;
    }

    public BigDecimal getSumB() {
        return sumB;
    }
}

然后,以这种方式使用它:

Map<String, ItemSum> map = list().stream()
    .collect(Collectors.groupingBy(
        Item::getKey, 
        Collector.of(
            ItemSum::new, 
            ItemSum::add,
            ItemSum::merge)));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM