预设需求场景,对一个企业做一个资金报表.
假设有一个资产预算表 属性有日期,事业群,部门,预算资金 ,花费资金.
对这个表数据进行处理,先清洗出预算小于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的意见,最终整合的上述代码!!