collections.unmodifiablelist返回运行时只读视图,不复制数据,拦截add/remove/set等操作并抛unsupportedoperationexception;但原始列表若被修改,视图内容同步变化,需配合防御性拷贝与私有封装才能真正防篡改。

Collections.unmodifiableList 是 Java 提供的轻量级只读包装工具,它不复制原始列表,而是返回一个“视图”——所有修改操作(如 add、remove、set)都会抛出 UnsupportedOperationException,从而在运行时防止意外篡改。
核心用法:包装已有 List
只需传入一个非 null 的 List 实例即可获得只读视图:
List<string> mutable = new ArrayList(Arrays.asList("a", "b", "c"));
List<string> readOnly = Collections.unmodifiableList(mutable);
</string></string>
⚠️ 注意:该方法不阻止原始列表被修改。如果后续还持有对 mutable 的引用并调用 mutable.add("d"),readOnly 的内容也会随之变化(因为是同一底层数据)。要真正防篡改,需确保原始列表不再被外部修改。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
安全实践:封装 + 不暴露原始引用
推荐在类中结合私有字段与 getter 封装,避免泄露可变副本:
- 将原始列表设为
private final,初始化后不再变更 - getter 返回
unmodifiableList视图 - 不提供任何返回原始列表或允许修改的 public 方法
示例:
public class Config {
private final List<string> allowedHosts;
public Config(List<string> hosts) {
// 防御性拷贝,避免调用方传入可变列表后继续修改
this.allowedHosts = Collections.unmodifiableList(
new ArrayList(Objects.requireNonNull(hosts))
);
}
public List<string> getAllowedHosts() {
return allowedHosts; // 返回只读视图
}
}
</string></string></string>
常见陷阱与注意事项
-
null 输入会抛 NPE:必须确保传入的 list 不为 null,建议用
Objects.requireNonNull显式检查 - 嵌套可变对象不受保护:若列表元素本身是可变对象(如自定义 POJO),只读视图无法阻止其内部状态被修改
-
不适用于并发场景:该视图不是线程安全的;若原始列表被其他线程并发修改,可能导致迭代异常(如
ConcurrentModificationException) - 性能开销极小:只是包装一层代理,无复制、无额外内存占用
替代方案对比(按适用场景)
-
List.copyOf(list)(Java 10+):创建**不可变副本**,更彻底防篡改,但有拷贝开销;要求 list 本身不为 null 且不含 null 元素 -
Arrays.asList(...):返回固定大小列表(不支持 add/remove),但支持 set;不是真正只读,也不防御原始数组修改 - Guava 的
ImmutableList.of()或ImmutableList.copyOf():功能更强,支持 builder、null 容忍、编译期不可变保证
不复杂但容易忽略细节。关键在于理解它只是运行时防护层,真正的安全性依赖设计约束。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










