[英]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.