collections.unmodifiablemap包装后的map,其keyset()返回的set不可修改,调用clear()等方法会直接抛出unsupportedoperationexception;该keyset是只读视图,不转发操作到原map,也不影响原始map内容。

Java 中 Collections.unmodifiableMap 包装后的 Map,其 keySet() 返回的 Set 也是不可修改的;调用 keySet().clear() 会直接抛出 UnsupportedOperationException,而非静默忽略或生效。
unmodifiableMap 的 keySet 是一个不可变视图
Collections.unmodifiableMap(m) 返回的是一个包装器(wrapper),它内部持有的 keySet() 并非原始 Map 的 keySet 副本,而是该不可变 Map 自己实现的只读 Set 视图。这个视图重写了所有可能修改结构的方法(如 add、remove、clear、retainAll 等),统一抛出 UnsupportedOperationException。
例如:
Map<string integer> origin = new HashMap();
origin.put("a", 1);
Map<string integer> unmod = Collections.unmodifiableMap(origin);
// 下面这行会立即抛出 UnsupportedOperationException
unmod.keySet().clear();
</string></string>
clear() 调用链实际发生在 UnmodifiableKeySet 上
该 keySet 的具体类型是 Collections.UnmodifiableMap.UnmodifiableKeySet(JDK 8+ 中为静态内部类)。它的 clear() 方法定义如下:
public void clear() {
throw new UnsupportedOperationException();
}
也就是说,拦截不是靠“检查底层是否可变”实现的,而是由该类主动拒绝所有变更操作——不依赖原始 Map 是否支持 clear,也不尝试转发调用。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
注意:keySet() 返回对象本身不可变,但不影响原始 Map
如果原始 Map 未被其他引用持有,仅通过 unmodifiableMap 暴露,则外部无法通过 keySet.clear() 影响它;但如果原始 Map 仍有可变引用,那么它的内容仍可能被修改,此时 unmodifiableMap 视图会反映这些变化(因为它是实时视图)。
关键点包括:
-
unmodifiableMap不冻结数据,只冻结接口行为 -
keySet().clear()不会清空原始 Map,也不会触发任何副作用 - 试图对 keySet 执行任何结构性修改都会在第一时间失败
- 遍历、contains、size 等只读操作正常工作
替代方案:如需真正隔离,应使用不可变副本
若目标是彻底防止底层 Map 被修改(包括来自其他引用的修改),unmodifiableMap 不够用。应考虑:
- JDK 9+:
Map.of()或Map.copyOf()(创建不可变快照) - Guava:
ImmutableMap.copyOf() - 手动拷贝构造新 Map 再包装(如
Collections.unmodifiableMap(new HashMap(original)))
这类方式切断了与原始 Map 的引用关联,才能确保“快照”完全独立。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










