Java移除同ID同状态重复Event对象 保留最大startTime记录报错
问题根因
你的代码存在几类核心问题,直接导致运行异常、返回空列表:
- 集合操作违规:for-each语法遍历List时直接调用
remove()修改集合结构,会触发ConcurrentModificationException;双重循环边遍历边删除会导致索引错位,遍历逻辑混乱,最终误删所有元素得到空列表。 - 低级拼写/语法错误:
- 类名错误:
Arraylist应为ArrayList,Events应为Event - 方法名错误:
getid()应为getId(),euqals()应为equals(),getStarttime()应为getStartTime() - 字符串比较错误:用
==比较Status内容,==比较的是对象内存地址不是字符串值,永远得不到正确匹配 - 日期格式错误:格式串里
yyyy-mm-dd的mm代表分钟,月份必须用大写MM,否则解析时间完全错误 - 变量名错误:定义的列表叫
results,删除时写的result.remove(e)变量不存在 - 状态值大小写不匹配:判断的状态是
"InProgress"(P大写),实际数据里是"Inprogress"(p小写),判断条件根本不会生效
- 类名错误:
- 去重逻辑缺陷:双重循环两两比较时,只要当前元素e比遍历到的e1时间早就删e,没有做分组保留最大时间的判断,哪怕是符合保留要求的最大时间元素,遍历到比它小的元素时也可能被误判删除。
正确实现
不要使用边遍历边删除的逻辑,直接按「ID+状态」做分组,每个分组只保留startTime最大的记录即可,逻辑清晰不会触发并发修改问题,也适配列表动态更新的场景。
Java 8+ 简洁实现(推荐)
用Stream的toMap做分组聚合,代码简洁易维护:
import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; public List<Event> removeDuplicates(List<Event> source) { // 注意日期格式:月份必须用大写MM DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); return new ArrayList<>(source.stream() // 过滤空对象、空ID的无效数据 .filter(Objects::nonNull) .filter(event -> event.getId() != null && !event.getId().isBlank()) // 按需打开下方注释,只保留Inprogress状态的记录 // .filter(event -> "Inprogress".equals(event.getStatus())) // 按ID+状态做分组,同组只保留时间最大的记录 .collect(Collectors.toMap( // 分组key:同ID同状态判定为同一组 event -> event.getId() + "_" + event.getStatus(), event -> event, // 同组两条记录冲突时,选择startTime更晚的记录保留 (oldVal, newVal) -> { LocalDateTime oldTime = LocalDateTime.parse(oldVal.getStartTime(), timeFormatter); LocalDateTime newTime = LocalDateTime.parse(newVal.getStartTime(), timeFormatter); return oldTime.isAfter(newTime) ? oldVal : newVal; } )) .values()); }
低版本Java兼容实现
不支持Stream的环境可以用HashMap临时存储分组结果,逻辑和上述实现一致:
import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; public List<Event> removeDuplicates(List<Event> source) { DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); Map<String, Event> groupContainer = new HashMap<>(); for (Event event : source) { if (event == null || event.getId() == null || event.getId().isBlank()) { continue; } // 按需打开下方注释,只保留Inprogress状态的记录 // if (!"Inprogress".equals(event.getStatus())) continue; String groupKey = event.getId() + "_" + event.getStatus(); Event existedEvent = groupContainer.get(groupKey); if (existedEvent == null) { groupContainer.put(groupKey, event); continue; } // 比较时间,将分组内记录替换为时间更晚的条目 LocalDateTime existedTime = LocalDateTime.parse(existedEvent.getStartTime(), timeFormatter); LocalDateTime currentTime = LocalDateTime.parse(event.getStartTime(), timeFormatter); if (currentTime.isAfter(existedTime)) { groupContainer.put(groupKey, event); } } return new ArrayList<>(groupContainer.values()); }
避坑提醒
- 所有字符串值比较必须用
equals(),绝对不要用== - 日期格式符严格区分大小写,使用前对照
DateTimeFormatter规则确认符号含义 - for-each遍历集合时禁止直接调用
add/remove修改集合结构,必须遍历删除请使用Iterator的remove()方法 - 去重、分组类逻辑优先用中间容器暂存结果,不要在原列表上反复遍历删除,逻辑混乱极易出bug
内容的提问来源于stack exchange,提问作者user15754268
相关产品推荐
相关产品推荐

