JJava 知识库
JAVA INTERVIEW

高频面试题

Java基础基础约 2 分钟

订单去重时明明用了 HashSet,结果还是出现重复数据,你会从 equals 和 hashCode 哪些地方排查?

参考回答约 2 分钟 · 口语表达
我的判断

HashSet 仍有重复,通常不是集合失效,而是业务去重键没有被 equals 和 hashCode 一致、稳定地表达。

我会先拿两条“看起来重复”的订单打印真正参与比较的字段和运行时类型。常见情况是 equals 比较了订单号,但 hashCode 还带着数据库主键;或者用了 Lombok,却把更新时间这类会变化的字段也生成进去了。这样两个对象要么落在不同桶里,要么加入 Set 后哈希值发生变化,后续就再也找不到原来的位置。

修复时不会为了迁就 Set 随便改整个订单实体。我更倾向于明确业务键,例如:

record OrderDedupKey(long tenantId, String requestNo) {}

然后用 Set<OrderDedupKey>Map<OrderDedupKey, Order> 去重。这样“什么叫同一笔订单”写在类型里,也不会受实体其他字段变化影响。

内存去重只能处理当前进程这一批数据。真正防止重复下单,数据库还需要 (tenant_id, request_no) 唯一约束,消费重试时按唯一键查询已有结果。

容易答偏踩坑误区
  • 只重写 equals,忘了同步重写 hashCode 相等对象必须产生相同哈希值。
  • 把可变字段放进哈希计算。 对象加入 Set 后再改状态或时间,会破坏集合定位。
  • 只靠 HashSet 保证业务幂等。 多实例、重启和消息重放都会绕过进程内集合。