如何用函数式风格通过Apache Common CSV按月分组并对数据求和
Java Stream 按周/月分组求和实现方案
核心思路
- 避免将解析后的日期转回字符串格式,直接使用
LocalDate对象内置的时间属性做分组依据,简化后续逻辑 - 利用Stream自带的
Collectors.groupingBy做分组,配合summingInt/reducing聚合器直接完成求和操作,全程符合函数式编程规范
优化实现代码
1. 定义业务数据实体(可选但更易维护)
如果是Java 16及以上版本可以直接用record,低版本替换为普通POJO即可:
// 按你的数据集字段调整,这里假设包含日期和待求和的数值两个核心字段 public record DataRow(LocalDate date, BigDecimal amount) {}
2. 优化CSV解析逻辑
直接将CSV行映射为业务实体,避免二次处理:
public List<DataRow> csvParser(String CSVFileName) throws IOException { DateTimeFormatter rawDateFormatter = DateTimeFormatter.ofPattern("M/d/yy"); // 用try-with-resources自动关闭资源 try(CSVParser csvParser = CSVParser.parse(Paths.get(CSVFileName), Charset.defaultCharset(), CSVFormat.DEFAULT)) { return csvParser .stream() // 按你实际的CSV列索引调整get的参数值 .map(record -> new DataRow( LocalDate.parse(record.get(0), rawDateFormatter), new BigDecimal(record.get(1)) )) .collect(Collectors.toList()); } }
3. 按月分组求和实现
public Map<String, BigDecimal> calculateSumByMonth(List<DataRow> dataRows) { DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM"); return dataRows.stream() .collect(Collectors.groupingBy( row -> row.date().format(monthFormatter), // 数值为整数的话可以替换为 Collectors.summingInt(DataRow::amount) Collectors.reducing(BigDecimal.ZERO, DataRow::amount, BigDecimal::add) )); }
4. 按周分组求和实现
默认用ISO标准周(周一为一周起始),如果需要周日为起始可以调整WeekFields配置:
public Map<String, BigDecimal> calculateSumByWeek(List<DataRow> dataRows) { // ISO周格式:年份-周数,自动处理跨年周问题 DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("YYYY-ww"); // 若要求周日为一周起始,用下方自定义逻辑替换formatter即可 // WeekFields weekFields = WeekFields.of(DayOfWeek.SUNDAY, 1); // Function<LocalDate, String> weekKeyGenerator = date -> date.getYear() + "-" + date.get(weekFields.weekOfWeekBasedYear()); return dataRows.stream() .collect(Collectors.groupingBy( row -> row.date().format(weekFormatter), Collectors.reducing(BigDecimal.ZERO, DataRow::amount, BigDecimal::add) )); }
注意事项
- 代码全程无可变中间变量,所有操作都是无副作用的函数式实现,符合作业要求
- 可根据你的数据集实际字段数量、求和字段类型灵活调整聚合逻辑,比如多字段求和可以用
teeing聚合器组合多个求和规则
内容的提问来源于stack exchange,提问作者mike kong
相关产品推荐
相关产品推荐

