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;
}
}
问题是在构建期间将 key 值传递给 ItemSum。之后我有一些解决方法来填充关键字段,但我想知道是否有办法在供应商中做到这一点并消除 ItemSum.
的默认构造函数
这是 toMap(keyMapper, valueMapper, mergeFunction)
收集器的工作,而不是 groupingBy
收集器的工作。
让我们添加一个构造函数
public ItemSum(Item item) {
this.key = item.getKey();
this.sumA = item.getA();
this.sumB = item.getB();
}
到classItemSum
。此构造函数基于 Item
初始化一个 ItemSum
。然后您可以删除默认构造函数(不需要)。然后你可以简单地拥有以下内容:
Map<String, ItemSum> map =
list().stream()
.collect(Collectors.toMap(Item::getKey, ItemSum::new, ItemSum::merge));
它所做的是将每个 Item
元素收集到一个由每个 Item
的键定义的映射 class 中。对于这个值,我们用一个 ItemSum
初始化它。当遇到同一个键的多个值时,我们将它们合并在一起。
总之,不能随心所欲
如果你让你的 ItemSum
class 在你的 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)));
在以下示例中,将分类器值提供给收集器的供应商函数的正确方法是什么:
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;
}
}
问题是在构建期间将 key 值传递给 ItemSum。之后我有一些解决方法来填充关键字段,但我想知道是否有办法在供应商中做到这一点并消除 ItemSum.
的默认构造函数这是 toMap(keyMapper, valueMapper, mergeFunction)
收集器的工作,而不是 groupingBy
收集器的工作。
让我们添加一个构造函数
public ItemSum(Item item) {
this.key = item.getKey();
this.sumA = item.getA();
this.sumB = item.getB();
}
到classItemSum
。此构造函数基于 Item
初始化一个 ItemSum
。然后您可以删除默认构造函数(不需要)。然后你可以简单地拥有以下内容:
Map<String, ItemSum> map =
list().stream()
.collect(Collectors.toMap(Item::getKey, ItemSum::new, ItemSum::merge));
它所做的是将每个 Item
元素收集到一个由每个 Item
的键定义的映射 class 中。对于这个值,我们用一个 ItemSum
初始化它。当遇到同一个键的多个值时,我们将它们合并在一起。
总之,不能随心所欲
如果你让你的 ItemSum
class 在你的 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)));