Java Stream如何调整groupingBy逻辑实现按指定天数日期窗口分组
实现方案
核心改动仅需调整Collectors.groupingBy的分组分类器,将原精确日期匹配改为按时间窗口编号匹配即可,原组内取最大值的逻辑无需修改。
前置说明
默认ObjectA.getDate()返回java.time.LocalDate类型(Java 8+推荐的日期类型),如果是旧版java.util.Date可参考文末的兼容方案。
完整代码实现
// 定义时间窗口天数 int daysWindow = 90; List<ObjectA> collapsed = list.stream().collect(Collectors.collectingAndThen( Collectors.groupingBy( // 替换原分组逻辑为时间窗口编号计算 obj -> { // 计算当前日期与纪元日(1970-01-01)的天数差,除以窗口大小取整得到窗口编号 long dayDiff = ChronoUnit.DAYS.between(LocalDate.EPOCH, obj.getDate()); return dayDiff / daysWindow; }, Collectors.maxBy(Comparator .comparing(ObjectA::getPriority1) .thenComparing(ObjectA::getPriority2) .thenComparing(ObjectA::getDate) .thenComparing(ObjectA::getId))), map -> map.values().stream() .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList())));
旧版java.util.Date兼容方案
如果ObjectA.getDate()返回的是java.util.Date,修改分组分类器的逻辑如下即可:
obj -> { // 注意时区可根据业务需要替换为指定时区,比如ZoneId.of("Asia/Shanghai") LocalDate localDate = obj.getDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); long dayDiff = ChronoUnit.DAYS.between(LocalDate.EPOCH, localDate); return dayDiff / daysWindow; }
逻辑说明
- 时间窗口编号计算逻辑:以1970-01-01为基准,每
daysWindow天划分为一个窗口,同一天窗口内的所有日期计算得到的编号完全一致,因此会被分到同一组 - 如果业务要求以集合内最早的日期为窗口起始基准,可以先提前计算集合的最小日期替换上述代码中的
LocalDate.EPOCH即可
内容的提问来源于stack exchange,提问作者Ed-Genesis
相关产品推荐
相关产品推荐

