putifabsent() 可高效实现重复过滤:键不存在时插入并返回 null,据此识别首次出现元素;需确保自定义 key 的 equals/hashcode 正确;多线程应使用 concurrenthashmap。

直接用 putIfAbsent() 做重复过滤,核心在于:它只在键不存在时才插入值,并返回 插入前的旧值(null 表示原来没这个键)。利用这个返回值,就能精准识别并跳过重复项,无需先 containsKey() 再 put(),避免两次哈希查找。
基础用法:识别首次出现的元素
比如处理一批用户 ID,只保留第一次出现的记录:
Map<string user> seenUsers = new HashMap();
List<user> uniqueUsers = new ArrayList();
for (User user : allUsers) {
// 如果 key(id)之前没出现过,putIfAbsent 返回 null → 是新数据
if (seenUsers.putIfAbsent(user.getId(), user) == null) {
uniqueUsers.add(user);
}
}
</user></string>
这里 putIfAbsent() 一次完成“查+插”,比先 containsKey() 再 put() 少一次哈希定位,性能更优。
配合自定义对象:确保 key 的 equals/hashCode 正确
如果用自定义类作 key(如 UserKey),必须重写 equals() 和 hashCode(),否则不同实例即使逻辑相同也会被当作不同 key:
- 不重写 → 每个 new 出来的对象 hash 值不同,
putIfAbsent()总认为是新 key - 正确重写 → 相同业务含义的 key 能命中同一个桶,真正去重
例如:UserKey(String name, int age) 必须基于 name 和 age 计算 hash 并比较相等性。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
进阶场景:过滤并统计重复次数
若还需知道某数据重复了多少次,可用 computeIfPresent() 或结合 merge():
Map<string integer> countMap = new HashMap();
for (String id : ids) {
// 首次出现:putIfAbsent 返回 null → 设为 1
// 再次出现:putIfAbsent 返回旧值(非 null)→ 跳过,后续用 merge 累加
if (countMap.putIfAbsent(id, 1) == null) {
continue; // 新数据,已设为 1
} else {
countMap.merge(id, 1, Integer::sum); // 已存在则累加
}
}
</string>
或者更简洁地全用 merge(),但 putIfAbsent() 在“只关心是否首次”时语义更清晰、开销略小。
注意并发安全:单线程用 HashMap,多线程换 ConcurrentHashMap
HashMap 不是线程安全的。若在多线程中过滤数据:
- 用
ConcurrentHashMap替代,它的putIfAbsent()是原子操作 - 避免用
Collections.synchronizedMap()包装 HashMap —— 它的putIfAbsent()不是原子的(先查后插,中间可能被其他线程干扰)
例如:ConcurrentHashMap<string boolean> seen = new ConcurrentHashMap();</string>,然后 seen.putIfAbsent(id, true) == null 即可安全判重。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










