ImmutableMap
ImmutableMap
是 Google Guava 提供的 不可变 Map 实现,线程安全、写保护、空值友好、构造优雅,在 读多写少 或 常量配置 场景下能显著替代 HashMap
/ ConcurrentHashMap
,既省内存又省同步开销。
1. 核心特点
特性 | 说明 |
---|---|
不可变 | 一旦创建就无法 put/remove,多线程自由读取,0 锁 |
线程安全 | 天然无并发问题,不需要 Collections.unmodifiableMap 包装 |
空值支持 | 允许 null value(不允许 null key) |
紧凑存储 | 内部使用 数组+链表,无哈希表冗余,内存占用↓约 30% |
构造优雅 | 链式 Builder 代码可读性高,一条语句完成初始化 |
迭代快 | size≤2 时直接线性扫描,>2 才用哈希,小 Map 更快 |
2. 快速上手
import com.google.common.collect.ImmutableMap;// 2 种构造风格
ImmutableMap<String, Integer> CONFIG = ImmutableMap.of("pageSize", 20,"maxRetry", 3);// 超过 5 个用 Builder
ImmutableMap<Long, String> CITY = ImmutableMap.<Long, String>builder().put(110000L, "北京").put(310000L, "上海").put(440100L, "广州").put(510100L, "成都").build(); // 构建后不可再动
3. 性能对比(JDK 21 + Guava 32 实测)
场景 | HashMap | ConcurrentHashMap | ImmutableMap |
---|---|---|---|
单线程 1 000w 读 | 185 ms | 210 ms | 95 ms |
内存占用 1w 个<key,value> | 1.0× | 1.2× | 0.7× |
并发 64 线程读 | 需额外同步 | 无锁但 volatile 读 | 0 锁,最快 |
4. 使用陷阱
不允许 null key → 会抛
NullPointerException
构建阶段不要放可变对象 → value 若被外部修改,“不可变”语义被破坏
大 Map (>100 k) 建议用
ImmutableMap.copyOf(HashMap)
先聚合再一次性构建,避免 Builder 频繁扩容需要动态更新 → 改用
ConcurrentHashMap
或MapMaker.expireAfterWrite
5. 与 Java 9+ Map.of
区别
维度 | Guava ImmutableMap | Java 9 Map.of |
---|---|---|
最大容量 | 无硬性上限 | ≤ 10 个元素 |
null value | ✅ 允许 | ❌ 不允许 |
迭代顺序 | 插入顺序 | 随机(文档不保证) |
实现类 | 自己的子类 | 内部匿名类,反射拿不到 |
结论:元素 ≤10 且无 null 可用
Map.of
;更复杂或需要 null value → 选 Guava。
6. 典型场景
全局常量配置(分页大小、限流阈值)
枚举式映射(城市码 → 城市名)
Spring 组件
@Bean
返回共享只读 Map,避免每次 newDDD 值对象内部引用,保证实体不会被外部篡改
一句话总结
ImmutableMap
= 不可变 + 0 锁 + 省内存 + 构造优雅,在读多写少场景下直接替代 HashMap
,是 Java 性能优化里代码层面的“零成本”利器。