如何在Java中对比两个Payment类型List并找差异,排查现有代码运行问题
现有代码存在的问题
- 空指针风险:没有对
rbsList、partnerList做非空校验,列表为null时遍历会直接抛出空指针异常;如果Payment的account字段为null,调用equals方法时也会触发空指针。 - 时间复杂度过高:两层嵌套循环的时间复杂度为O(n*m),当两个列表的元素量级较大(比如超过1万条)时,运行效率极低,甚至会触发你捕获的
OutOfMemoryError或者超时问题。 - 匹配逻辑漏洞:如果同一个
account+sum的组合在其中一个列表中出现多次,例如rbsList有2条相同组合的记录,partnerList只有1条,现有代码会把rbsList的两条都标记为匹配,不符合一对一匹配的业务逻辑。 - 业务侵入性强:需要在
Payment类中额外新增exist字段,修改了核心业务类的结构,适用场景受限。 - 异常处理不合理:捕获异常后仅打印堆栈,后续的流处理逻辑仍会执行,最终得到的不匹配列表结果是错误的。
正确实现方案
推荐使用哈希表优化的实现,无需修改Payment类结构,时间复杂度降低到O(n+m),性能提升明显:
import java.util.*; import java.util.stream.Collectors; import java.util.AbstractMap.SimpleEntry; private List<Payment> rbsList; private List<Payment> partnerList; private List<Payment> notMatchedRBS; private List<Payment> notMatchedPartner; public void compare() { // 非空校验 if (rbsList == null) rbsList = Collections.emptyList(); if (partnerList == null) partnerList = Collections.emptyList(); // 构造partner侧的匹配键计数Map,键为<account, sum>,值为对应记录的队列 Map<SimpleEntry<String, Integer>, Queue<Payment>> partnerMap = new HashMap<>(); for (Payment p : partnerList) { String account = p.getAccount() == null ? "" : p.getAccount(); Integer sum = p.getSum(); SimpleEntry<String, Integer> key = new SimpleEntry<>(account, sum); partnerMap.computeIfAbsent(key, k -> new LinkedList<>()).offer(p); } Set<Payment> matchedPartner = new HashSet<>(); notMatchedRBS = new ArrayList<>(); // 遍历rbs列表匹配 for (Payment rbs : rbsList) { String account = rbs.getAccount() == null ? "" : rbs.getAccount(); Integer sum = rbs.getSum(); SimpleEntry<String, Integer> key = new SimpleEntry<>(account, sum); if (partnerMap.containsKey(key) && !partnerMap.get(key).isEmpty()) { // 取出一个匹配的partner标记为已匹配 matchedPartner.add(partnerMap.get(key).poll()); } else { notMatchedRBS.add(rbs); } } // 收集partner侧未匹配的记录 notMatchedPartner = partnerList.stream() .filter(p -> !matchedPartner.contains(p)) .collect(Collectors.toList()); }
如果一定要保留原有exist字段的实现,可以在原有逻辑基础上补充空校验、优化匹配逻辑即可,但依然不推荐在数据量大的场景下使用。
内容的提问来源于stack exchange,提问作者my pochta
相关产品推荐
相关产品推荐

