我有一个GroupItem对象的列表:
public class GroupItem {
Group group;
BigDecimal value;
...
}
我想实现的是一个地图,其中汇总了相同组键的值。我以以下方式实现(略微重构的变体,但仍然不够优雅):
List<GroupItem> items = generateGroupItemList();
Map<Group, BigDecimal> resultMap = new HashMap<>();
for (GroupItem item : items) {
resultMap.put(item.getGroup(), resultMap.getOrDefault(item.getGroup(), BigDecimal.ZERO).add(item.getValue()));
}
此变体看起来很丑,并且缺乏可读性。我尝试使用流,但未取得任何积极成果。总体思路是围绕Collectors.groupingBy()和类似的内容:
items.stream().collect(
Collectors.groupingBy(
GroupItem::getGroup,
Collectors.reducing(GroupItem:getValue, /*BigDecimal::add*/)
));
除了上述变体以外,还有其他更优雅的方法来达到预期的效果吗?
使用Stream
,可以用toMap
执行Collectors
:
Map<Group, BigDecimal> resultMap = items.stream()
.collect(Collectors.toMap(GroupItem::getGroup,
GroupItem::getValue, BigDecimal::add));
您可以使用merge方法:
List<GroupItem> items = generateGroupItemList();
Map<Group, BigDecimal> resultMap = new HashMap<>();
for (GroupItem item : items) {
resultMap.merge(item.getGroup(), item.getValue(), BigDecimal::add);
}
您可以使用Collectors.mapping和Collectors.collectingAndThen的组合
Map<Group, BigDecimal> res = items.stream()
.collect(Collectors.groupingBy(GroupItem::getGroup,
Collectors.mapping(GroupItem::getValue,
Collectors.collectingAndThen(Collectors.toList(),
list -> list.stream().reduce(BigDecimal.ZERO, BigDecimal::add)))));
或更简单地说,您也可以使用computeIfAbsent
for(GroupItem item : items) {
resultMap.computeIfAbsent(item.getGroup(), k->BigDecimal.ZERO).add(item.getValue());
}