Java中按日期对对象列表进行分组的策略与实践

来源:菜鸟站长作者:关中王头衔:草根站长
导读:本期聚焦于小伙伴创作的《Java中按日期对对象列表进行分组的策略与实践》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java中按日期对对象列表进行分组的策略与实践》有用,将其分享出去将是对创作者最好的鼓励。

在Java业务开发中,处理包含日期字段的对象集合时,按照日期维度对数据进行归类是高频需求,比如统计每日订单量、按月汇总用户消费金额等场景都需要用到日期分组能力。不同的业务场景对日期精度要求不同,对应的实现策略也存在差异,下面介绍几种常用的实现方式。

Java中按日期对对象列表进行分组的策略与实践

基础场景准备

首先定义一个包含日期属性的示例对象,后续所有分组操作都基于该对象列表展开:

import java.time.LocalDateTime;

public class Order {
    private String orderId;
    private LocalDateTime createTime;
    private Double amount;

    public Order(String orderId, LocalDateTime createTime, Double amount) {
        this.orderId = orderId;
        this.createTime = createTime;
        this.amount = amount;
    }

    // getter和setter方法
    public String getOrderId() {
        return orderId;
    }

    public LocalDateTime getCreateTime() {
        return createTime;
    }

    public Double getAmount() {
        return amount;
    }
}

按日期分组的核心策略

1. 使用Stream API的groupingBy方法

Java 8引入的Stream API提供了Collectors.groupingBy方法,可以非常简洁地实现分组逻辑,这也是目前最推荐的实现方式。

按天分组

如果需要按照创建日期的天维度分组,只需要将日期转换为当天的起始时间作为分组键即可:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class DateGroupDemo {
    public static void main(String[] args) {
        // 构造测试数据
        List<Order> orderList = new ArrayList<>();
        orderList.add(new Order("001", LocalDateTime.of(2024, 3, 10, 14, 30), 100.0));
        orderList.add(new Order("002", LocalDateTime.of(2024, 3, 10, 16, 45), 200.0));
        orderList.add(new Order("003", LocalDateTime.of(2024, 3, 11, 9, 20), 150.0));

        // 按天分组,将日期格式化为yyyy-MM-dd字符串作为分组键
        DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        Map<String, List<Order>> orderByDay = orderList.stream()
                .collect(Collectors.groupingBy(order -> 
                        order.getCreateTime().format(dayFormatter)));

        // 输出分组结果
        orderByDay.forEach((date, orders) -> {
            System.out.println("日期:" + date + ",订单数量:" + orders.size());
        });
    }
}

按月分组

按月分组的逻辑和按天分组类似,只需要调整日期格式即可:

import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.stream.Collectors;

public class MonthGroupDemo {
    public static void main(String[] args) {
        List<Order> orderList = new ArrayList<>();
        orderList.add(new Order("001", LocalDateTime.of(2024, 3, 10, 14, 30), 100.0));
        orderList.add(new Order("002", LocalDateTime.of(2024, 3, 25, 16, 45), 200.0));
        orderList.add(new Order("003", LocalDateTime.of(2024, 4, 5, 9, 20), 150.0));

        // 按月分组,格式化为yyyy-MM
        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
        Map<String, List<Order>> orderByMonth = orderList.stream()
                .collect(Collectors.groupingBy(order -> 
                        order.getCreateTime().format(monthFormatter)));

        orderByMonth.forEach((month, orders) -> {
            System.out.println("月份:" + month + ",订单总金额:" + 
                    orders.stream().mapToDouble(Order::getAmount).sum());
        });
    }
}

2. 传统循环实现分组

如果项目使用的Java版本低于8,无法使用Stream API,也可以通过传统循环实现分组逻辑:

import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LoopGroupDemo {
    public static void main(String[] args) {
        List<Order> orderList = new ArrayList<>();
        orderList.add(new Order("001", LocalDateTime.of(2024, 3, 10, 14, 30), 100.0));
        orderList.add(new Order("002", LocalDateTime.of(2024, 3, 10, 16, 45), 200.0));
        orderList.add(new Order("003", LocalDateTime.of(2024, 3, 11, 9, 20), 150.0));

        DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        Map<String, List<Order>> orderByDay = new HashMap<>();

        for (Order order : orderList) {
            String dayKey = order.getCreateTime().format(dayFormatter);
            // 如果分组键不存在,先初始化列表
            if (!orderByDay.containsKey(dayKey)) {
                orderByDay.put(dayKey, new ArrayList<>());
            }
            orderByDay.get(dayKey).add(order);
        }

        orderByDay.forEach((date, orders) -> {
            System.out.println("日期:" + date + ",订单数量:" + orders.size());
        });
    }
}

分组后的常见处理操作

分组结果排序

默认情况下,HashMap的遍历顺序是不固定的,如果需要按照日期顺序输出分组结果,可以对键进行排序:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class SortedGroupDemo {
    public static void main(String[] args) {
        List<Order> orderList = new ArrayList<>();
        orderList.add(new Order("001", LocalDateTime.of(2024, 3, 10, 14, 30), 100.0));
        orderList.add(new Order("002", LocalDateTime.of(2024, 3, 12, 16, 45), 200.0));
        orderList.add(new Order("003", LocalDateTime.of(2024, 3, 11, 9, 20), 150.0));

        DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        Map<String, List<Order>> orderByDay = orderList.stream()
                .collect(Collectors.groupingBy(order -> 
                        order.getCreateTime().format(dayFormatter)));

        // 按照日期字符串排序输出,注意日期格式需要符合字典序
        orderByDay.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .forEach(entry -> {
                    System.out.println("日期:" + entry.getKey() + ",订单数量:" + entry.getValue().size());
                });
    }
}

分组后聚合计算

除了简单的分组,很多时候还需要对分组后的数据进行聚合,比如求和、计数、求平均值等,Stream API也提供了对应的支持:

import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class AggregateGroupDemo {
    public static void main(String[] args) {
        List<Order> orderList = new ArrayList<>();
        orderList.add(new Order("001", LocalDateTime.of(2024, 3, 10, 14, 30), 100.0));
        orderList.add(new Order("002", LocalDateTime.of(2024, 3, 10, 16, 45), 200.0));
        orderList.add(new Order("003", LocalDateTime.of(2024, 3, 11, 9, 20), 150.0));

        DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 按天分组并直接计算每组的订单总金额
        Map<String, Double> dayTotalAmount = orderList.stream()
                .collect(Collectors.groupingBy(
                        order -> order.getCreateTime().format(dayFormatter),
                        Collectors.summingDouble(Order::getAmount)
                ));

        dayTotalAmount.forEach((date, total) -> {
            System.out.println("日期:" + date + ",总金额:" + total);
        });
    }
}

注意事项

  • 日期格式选择:分组使用的日期格式字符串需要符合业务需求,同时如果后续需要排序,格式最好满足字典序,比如yyyy-MM-dd格式就比yyyy年MM月dd日更适合排序。
  • 时区问题:如果系统涉及多时区场景,需要先统一时区再处理日期,避免出现分组错误。
  • 空值处理:如果对象列表中存在createTime为null的情况,需要提前过滤或者做空值判断,避免分组时出现空指针异常。

Java日期分组对象列表MapStream_API修改时间:2026-07-14 09:30:36

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。