You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java Stream将多场所货币金额转换为聚合Map<Currency, BigDecimal>

用Java Stream实现多场所货币金额汇总

这问题我熟,用Java Stream来做其实很直观,核心就是两步:把所有工作场所的货币-金额数据扁平化,再按货币类型分组求和。下面给你拆解具体实现,附上可运行的代码示例:

第一步:定义工作场所模型

首先我们需要一个Workplace类,用来表示单个工作场所的货币金额数据:

import java.math.BigDecimal;
import java.util.Currency;
import java.util.Map;

public class Workplace {
    private final Map<Currency, BigDecimal> currencyAmounts;

    public Workplace(Map<Currency, BigDecimal> currencyAmounts) {
        this.currencyAmounts = currencyAmounts;
    }

    public Map<Currency, BigDecimal> getCurrencyAmounts() {
        return currencyAmounts;
    }
}

第二步:核心Stream汇总逻辑

假设你已经有了一个包含所有工作场所的List<Workplace>,我们可以用Stream的flatMap和分组收集器来完成汇总:

import java.math.BigDecimal;
import java.util.Currency;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CurrencySumDemo {
    public static void main(String[] args) {
        // 模拟测试数据:两个工作场所的货币金额
        Workplace shop1 = new Workplace(Map.of(
                Currency.getInstance("USD"), new BigDecimal("20"),
                Currency.getInstance("EUR"), new BigDecimal("40")
        ));

        Workplace shop2 = new Workplace(Map.of(
                Currency.getInstance("USD"), new BigDecimal("50"),
                Currency.getInstance("EUR"), new BigDecimal("10")
        ));

        List<Workplace> allWorkplaces = List.of(shop1, shop2);

        // 核心汇总代码
        Map<Currency, BigDecimal> totalByCurrency = allWorkplaces.stream()
                // 1. 扁平化:把每个场所的货币Map拆成单个Entry流
                .flatMap(workplace -> workplace.getCurrencyAmounts().entrySet().stream())
                // 2. 分组求和:按货币类型分组,对同货币的金额累加
                .collect(Collectors.groupingBy(
                        Map.Entry::getKey, // 分组键:货币类型
                        Collectors.reducing(
                                BigDecimal.ZERO, // 累加初始值(避免空指针)
                                Map.Entry::getValue, // 提取要累加的金额
                                BigDecimal::add // 累加操作
                        )
                ));

        // 打印结果验证
        totalByCurrency.forEach((currency, total) ->
                System.out.printf("%s: %s%n", currency.getCurrencyCode(), total));
        // 输出结果:
        // USD: 70
        // EUR: 50
    }
}

关键步骤解释

  • 扁平化处理:flatMap的作用是把每个工作场所的Map<Currency, BigDecimal>转换成Stream<Map.Entry<Currency, BigDecimal>>,这样所有场所的货币-金额对都变成了流中的独立元素,方便后续统一分组。
  • 分组求和:Collectors.groupingBy负责按货币类型分组,下游收集器Collectors.reducing则完成同一组内的金额累加:
    • BigDecimal.ZERO作为初始值,确保即使某个货币没有任何金额数据时,也能返回0(增强代码健壮性);
    • Map.Entry::getValue用来提取每个Entry中的金额值;
    • BigDecimal::add是BigDecimal的累加方法,因为BigDecimal是不可变类,这个操作会返回新的BigDecimal实例,线程安全。

Java 12+ 简化写法

如果你使用的是Java 12及以上版本,可以用Collectors.summingBigDecimal来替代reducing,代码会更简洁:

.collect(Collectors.groupingBy(
        Map.Entry::getKey,
        Collectors.summingBigDecimal(Map.Entry::getValue)
));

注意事项

  • Currency是单例类,同一个货币代码(比如"USD")的Currency实例是同一个对象,所以作为Map的键不会有问题;
  • 确保所有金额都是BigDecimal类型(不要用double,避免精度丢失),这和你的需求完全匹配。

内容的提问来源于stack exchange,提问作者Артем Потешкин

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:02:16