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

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。此构造函数基于ItemSum初始化一个Item。然后,您可以删除默认构造函数(不需要)。然后,您可以简单地拥有以下内容:
Map<String, ItemSum> map =
    list().stream()
          .collect(Collectors.toMap(Item::getKey, ItemSum::new, ItemSum::merge));

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

关于java - Java 8 Collector.groupingBy通过下游的分类器值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36794656/

10-09 04:43