collections.empty_map 是不可变空map单例,非null故可安全调用查询方法,但所有修改操作均抛unsupportedoperationexception。

为什么 Collections.EMPTY_MAP 不是 null,但又不能往里 put?
它本质是一个不可变的空 Map 实例,内部用单例对象实现,不是 null,所以能安全调用 size()、isEmpty() 等方法;但它禁止所有修改操作——一旦调用 put()、remove() 或 clear(),立刻抛出 UnsupportedOperationException。
- 常见错误现象:
NullPointerException不会出现,但运行时突然崩在put()上,堆栈里看到UnsupportedOperationException却没意识到是用了只读集合 - 适用场景:作为方法返回值兜底,比如 DAO 查询无结果时返回
Collections.EMPTY_MAP,避免上层判 null;或初始化字段时做轻量占位 - 注意它不等于
new HashMap():后者可变、可扩容、有哈希桶结构;前者内存固定、无任何内部数组、连entrySet()都是空不可变视图
Collections.EMPTY_MAP 和 Map.of()(Java 9+)怎么选?
两者都返回不可变 map,但语义和兼容性完全不同。
Ke361是一个开源的淘宝客系统,基于最新的ThinkPHP3.2版本开发,提供更方便、更安全的WEB应用开发体验,采用了全新的架构设计和命名空间机制, 融合了模块化、驱动化和插件化的设计理念于一体,以帮助想做淘宝客而技术水平不高的朋友。突破了传统淘宝客程序对自动采集商品收费的模式,该程序的自动 采集模块对于所有人开放,代码不加密,方便大家修改。集成淘点金组件,自动转换淘宝链接为淘宝客推广链接。K
-
Collections.EMPTY_MAP是 Java 1.2 就有的老 API,类型是原始Map,泛型擦除后容易引发类型不安全警告(比如赋给Map<string integer></string>会告警 unchecked cast) -
Map.of()是类型安全的:直接推导泛型,返回Map<k></k>,且编译期就拒绝重复 key;但它要求至少 Java 9,低版本用不了 - 性能上没实质差异:都是单例 + 零容量,但
Map.of()在空 map 场景下实际也复用同一个静态实例(OpenJDK 实现中),不是每次都 new
替代方案:什么时候该用 ImmutableMap.of()(Guava)?
如果你已经在用 Guava,且需要明确表达“这个空 map 是故意不可变的”,ImmutableMap.of() 比 Collections.EMPTY_MAP 更直白、类型更干净。
- 不会触发泛型 unchecked 警告:返回的是真正的
ImmutableMap<k></k> - 语义清晰:名字自带
Immutable,别人一眼看懂不能改;而Collections.EMPTY_MAP名字只说“空”,不说“不可变”,容易误判 - 兼容性代价:引入 Guava 依赖;如果只是偶尔用空 map,没必要为这点清晰度加一个 jar
- 注意别混用:
ImmutableMap.of()返回的是 Guava 类型,不能直接赋给 JDK 的Map变量而不声明类型(虽然接口兼容,但 IDE 可能报冗余转换)
最容易被忽略的坑:序列化和反射访问
Collections.EMPTY_MAP 是可序列化的,但它的反序列化行为和你想象的可能不一样。
- 反序列化后得到的仍是同一个单例对象(JDK 保证),不是新实例——所以
==比较仍为 true,这点常被忽略 - 反射调用
put()同样失败:哪怕绕过编译检查,运行时照样抛UnsupportedOperationException,因为底层实现压根没提供修改逻辑 - 调试时注意:IDE 的变量查看器可能显示它“像一个普通 map”,但点开
table或entrySet字段会发现全是 null 或空集合,没有真实数据结构支撑









