如何按日期参数操作HashMap中对象列表 实现事件间隔校验删除
实现方案
首先先修正你原有代码的两个基础问题:
- 所有profileID共用同一个全局
eventList实例,会导致不同profile的事件完全混存,必须为每个profileID初始化独立的事件列表 - 事件列表用
List<Object>声明会丢失类型信息,后续取事件日期需要强制类型转换,容易抛出类型转换异常,建议定义明确的事件类型(下文统一用Event作为事件类名,包含LocalDateTime eventTime事件时间字段、对应的getter方法)
步骤1:修正数据填充逻辑
原遍历代码里cpToEvent变量未定义,结合你的需求,正确的事件分组填充逻辑如下:
HashMap<String, List<Event>> profileMap = new HashMap<>(); // Plist为你传入的Profile对象列表 for (Profile profile : Plist) { String profileId = profile.getprofileID(); // 不存在当前profile的键时,新建独立的事件列表 profileMap.putIfAbsent(profileId, new ArrayList<>()); // 取出当前profile对应的事件列表,添加关联事件 // 注意替换成你实际获取当前profile对应事件的逻辑 Event bindEvent = profile.getBindEvent(); profileMap.get(profileId).add(bindEvent); }
步骤2:按事件时间对每个profile的事件列表排序
Java 8+直接用List.sort方法结合比较器即可完成排序,不需要自己写排序算法:
// 遍历所有profile的事件列表,按事件时间升序排序(早发生的事件排在前面) for (List<Event> events : profileMap.values()) { events.sort(Comparator.comparing(Event::getEventTime)); }
如果你用的是旧版java.util.Date作为事件时间字段,直接把比较器里的Event::getEventTime换成对应的Date字段getter即可,Date类本身实现了比较接口,可直接排序。
步骤3:遍历排序后的列表,删除间隔超1年的事件
不要在普通正序for循环里直接调用list.remove()删除元素,会触发索引偏移导致漏遍历,推荐用迭代器遍历删除。时间间隔计算优先用java.time.Period,避免手动算毫秒差遇到闰年、夏令时、时区导致的计算误差:
// 定义1年的间隔阈值 private static final int MAX_ALLOWED_YEAR_GAP = 1; for (List<Event> events : profileMap.values()) { // 空列表、只有1个事件的列表不存在相邻间隔,直接跳过 if (events.size() <= 1) { continue; } Iterator<Event> iterator = events.iterator(); // 取第一个事件作为初始比对基准 Event lastValidEvent = iterator.next(); while (iterator.hasNext()) { Event currentEvent = iterator.next(); // 转换为LocalDate计算年差,忽略时分秒的影响 LocalDate lastDate = lastValidEvent.getEventTime().toLocalDate(); LocalDate currentDate = currentEvent.getEventTime().toLocalDate(); int yearGap = Period.between(lastDate, currentDate).getYears(); if (yearGap > MAX_ALLOWED_YEAR_GAP) { // 间隔超过1年,删除当前事件,保留更早的有效事件作为下一轮基准 // 如果你需要间隔超1年时同时删除前后两个事件,可以维护一个待删除集合,遍历完成后批量移除 iterator.remove(); } else { // 间隔符合要求,更新比对基准为当前事件 lastValidEvent = currentEvent; } } }
如果你的事件时间字段是旧的java.util.Date类型,可以用下面的工具方法转成LocalDate再计算间隔:
private static LocalDate dateToLocalDate(Date date) { return date.toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate(); }
注意事项
- 禁止用两个时间的毫秒差除以
365*24*60*60*1000的方式计算年间隔,闰年、夏令时切换都会导致计算结果错误 - 如果你的需求是相邻事件间隔超1年时删除时间更早的事件、或者两个事件都删除,不要在迭代器里连续调用两次
remove(),可以先把所有待删除的事件收集到一个Set里,遍历完成后调用events.removeAll(待删除集合),避免遍历状态异常 - 排序前要确保所有事件的时间字段非空,否则会抛出空指针异常,可以在排序前加过滤逻辑移除时间为空的无效事件
内容的提问来源于stack exchange,提问作者Ujjwal Kuikel
相关产品推荐
相关产品推荐

