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

als*_*sid 3 java java-8 java-stream collectors

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

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

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

Tun*_*aki 5

这是toMap(keyMapper, valueMapper, mergeFunction)收藏家的工作,而不是groupingBy收藏家.

让我们添加一个构造函数

public ItemSum(Item item) {
    this.key = item.getKey();
    this.sumA = item.getA();
    this.sumB = item.getB();
}
Run Code Online (Sandbox Code Playgroud)

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

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

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