containskey()时间复杂度o(1),基于哈希查找;containsvalue()时间复杂度o(n),需全量遍历,二者性能呈数量级差异,应避免在大数据量或高频场景下使用containsvalue()。

containsKey() 判断键是否存在,本质是哈希查找
containsKey() 在 HashMap、ConcurrentHashMap 等基于哈希表实现的 Map 中时间复杂度为 O(1),它只检查 key 是否落在某个桶中,不涉及 value 的遍历。
常见误用是拿 null 做参数:如果 Map 允许 null 键(如 HashMap),containsKey(null) 是合法的;但若用的是 ConcurrentHashMap,传入 null 会直接抛 NullPointerException —— 它明确禁止 null 键和 null 值。
- 确认 Map 实现类是否允许 null 键(
HashMap✅,ConcurrentHashMap❌) - 避免在多线程场景下混用
containsKey()和后续的get(),可能因竞态导致结果不一致;应改用computeIfPresent()或putIfAbsent()等原子操作 - 不要用
containsKey()来“预检再取值”,多数情况下直接map.get(key)并判 null 更简洁安全
containsValue() 判断值是否存在,本质是全量遍历
containsValue() 在几乎所有标准 Map 实现中都是 O(n) 操作,它必须逐个比较每个 entry 的 value。即使 Map 很大,也无法跳过遍历 —— 因为 value 不参与哈希计算,也没有索引结构支撑快速查找。
典型卡顿场景:在循环里反复调用 containsValue("xxx") 查找某字符串,尤其当 Map 有上万条数据时,很容易拖慢接口响应。
- 如果频繁按 value 查询,考虑反向建一个
Map<value key></value>,或改用Set存储所有 value(注意 value 重复时需用Multiset类库) -
containsValue()对 null 值的处理是统一的:HashMap和ConcurrentHashMap都支持containsValue(null),只要真有 entry 的 value 是 null 就返回 true - 自定义对象作为 value 时,务必重写
equals()和hashCode(),否则containsValue(obj)可能永远返回 false(哪怕内容相同)
containsKey 与 containsValue 的性能差异有多大
差距不是“有点慢”,而是数量级差异。对一个含 10 万 entry 的 HashMap:
-
containsKey("known-key"):通常在纳秒级完成(一次哈希 + 一次桶内链表/红黑树查找) -
containsValue("known-value"):平均要遍历 5 万次,每次调用equals(),实测常达毫秒级
更关键的是,containsValue() 无法被 JIT 有效优化,且在并发环境下容易引发 CPU 缓存行争用 —— 即使只是读操作,多个线程同时调用也会互相干扰。
替代方案:什么时候该放弃 containsValue
除非数据量极小(containsValue()。
- 想查“某个值是否被使用过” → 改用独立的
Set<value></value>维护已用值集合,增删查都是 O(1) - 想查“哪个 key 对应这个 value” → 用
entrySet().stream().filter(...).findFirst()显式表达意图,比containsValue()+ 再次遍历更可控 - 用 Guava 的
BiMap或 Apache Commons Collections 的BidiMap,它们天然支持双向查找,但要注意内存开销翻倍
真正难处理的是 value 本身不可哈希(比如含可变字段的类)、或业务要求模糊匹配(如“value 包含某子串”)——这时候 containsValue() 本身就不是解法,得换思路做索引或用专用检索库。










