在以下示例中,将分类器值提供给收集器的供应商功能的正确方法是:
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/