java8的Stream的 清洗,分组,聚合演示demo

文章展示了如何使用Java8的StreamAPI对资产预算表数据进行清洗、分组和聚合操作,特别是对预算小于5的记录。通过并行流、减少数据传输、高效数据结构和算法以及分批处理等方法,优化大量数据处理的性能。
摘要由CSDN通过智能技术生成

预设需求场景,对一个企业做一个资金报表.

假设有一个资产预算表 属性有日期,事业群,部门,预算资金 ,花费资金.

对这个表数据进行处理,先清洗出预算小于5的 在根据日期,事业群进行分组,然后汇总预算资金和花费资金,最终合成一个新的对象集合 属性是 日期,事业群,预算资金,花费资金。

1. 定义AssetBudget类:

 

@Data
public class AssetBudget {

    /**
     * 日期
     */
    private Date date;
    /**
     * 事业群
     */
    private String businessGroup;
    /**
     * 部门
     */
    private String department;

    /**
     * 预算资金
     */
    private double budgetAmount;

    /**
     * 花费资金
     */
    private double spentAmount;

    public AssetBudget(Date date, String businessGroup, String department, double budgetAmount, double spentAmount) {
        this.date = date;
        this.businessGroup = businessGroup;
        this.department = department;
        this.budgetAmount = budgetAmount;
        this.spentAmount = spentAmount;
    }

2. 使用Java 8的Stream API进行操作:

public static void main(String[] args) {
  List<AssetBudget> assetBudgets = new ArrayList<>(); // 初始资产预算列表
        final DateTime date1 = DateUtil.date();
        final DateTime yesterday = DateUtil.yesterday();
        assetBudgets.add(
                new AssetBudget(date1, "事业群1", "A", 10.1, 12.5)
        );
        assetBudgets.add(
                new AssetBudget(yesterday, "事业群1", "A", 10, 13.5)
        );
        assetBudgets.add(
                new AssetBudget(date1, "事业群2", "C", 15, 21)
        );
        assetBudgets.add(
                new AssetBudget(yesterday, "事业群2", "C", 13, 17)
        );

        assetBudgets.add(
                new AssetBudget(date1, "事业群1", "B", 5, 6.5)
        );

        assetBudgets.add(
                new AssetBudget(yesterday, "事业群1", "B", 7, 5.5)
        );


        // 清洗预算小于5的数据
        List<AssetBudget> cleanedAssetBudgets = assetBudgets.stream()
                .filter(assetBudget -> assetBudget.getBudgetAmount() >= 5)
                .collect(Collectors.toList());

        // 根据日期和事业群进行分组
        Map<Date, Map<String, List<AssetBudget>>> groupedAssetBudgets = cleanedAssetBudgets.stream()
                .collect(Collectors.groupingBy(AssetBudget::getDate,
                        Collectors.groupingBy(AssetBudget::getBusinessGroup)));

        List<AssetBudget> result = new ArrayList<>();

        // 聚合预算资金和花费资金
        groupedAssetBudgets.forEach((date, businessGroupMap) -> {
            businessGroupMap.forEach((businessGroup, assetBudgetList) -> {
                double totalBudgetAmount = assetBudgetList.stream()
                        .mapToDouble(AssetBudget::getBudgetAmount)
                        .sum();
                double totalSpentAmount = assetBudgetList.stream()
                        .mapToDouble(AssetBudget::getSpentAmount)
                        .sum();

                AssetBudget aggregatedAssetBudget = new AssetBudget(date, businessGroup, "", totalBudgetAmount, totalSpentAmount);
                result.add(aggregatedAssetBudget);
            });
        });

        // 输出结果
        result.forEach(System.out::println);
}

 

这个方法的效率相对较高,因为使用了Java 8的Stream API,它是基于内部迭代的,可以自动优化迭代过程。然而,对于几十万条数据的处理,可能会遇到性能瓶颈,特别是在分组和聚合操作上。

为了提高处理大量数据的性能,可以考虑以下优化方法:

1. 使用并行流(Parallel Stream):将顺序流转换为并行流,以便利用多核处理器并发执行操作。将`stream()`替换为`parallelStream()`即可。请注意,并行流可能会影响到线程安全,需要确保在并行操作时不会有线程安全问题。

 

List<AssetBudget> cleanedAssetBudgets = assetBudgets.parallelStream()
        .filter(assetBudget -> assetBudget.getBudgetAmount() >= 1000)
        .collect(Collectors.toList());

2. 减少数据传输:在数据库查询时,可以通过聚合函数(如SUM、COUNT等)和GROUP BY子句对数据进行预处理,从而减少从数据库到应用程序的数据传输量。这样可以减轻应用程序对数据的处理负担。

3. 使用更高效的数据结构和算法:在某些情况下,使用更高效的数据结构和算法可以提高性能。例如,在聚合操作中,可以考虑使用`HashMap`或`ConcurrentHashMap`来存储和更新分组数据,而不是使用嵌套循环。

4. 分批处理:将大量数据分成较小的批次进行处理,可以降低内存消耗,并减少GC(垃圾回收)的影响。

5. 考虑使用专门针对大数据处理的框架.

请注意,优化方法的实际效果取决于具体的数据结构和执行环境。在进行优化时,建议先测试和分析性能瓶颈,然后针对性地进行优化。

 

注:在公司开发中,有类似需求,我当时想试试通过代码而非数据实现,请教GPT的意见,最终整合的上述代码!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值