Java不可变集合核心是“创建即冻结”,推荐Java9+ of()工厂方法;Collections.unmodifiableXxx仅加只读外壳,需先拷贝再封装;泛型类中应安全初始化并返回不可变视图。

Java 中不可变集合的初始化和数据保护,核心在于“创建即冻结”和“隔离底层可变性”。不是靠运行时拦截,而是靠编译期约束、构造时复制、以及不暴露可变引用这三重保障。
用 Java 9+ of() 系列工厂方法直接创建真不可变实例
这是最推荐的初始化方式,适用于元素数量固定、内容明确的场景。
- List.of("a", "b", "c"):创建不可变列表,支持任意数量(重载至10个参数),不允许 null,重复元素合法
- Set.of(1, 2, 3):自动去重,元素唯一且不可为 null;传入重复值会抛 IllegalArgumentException
- Map.of("k1", 1, "k2", 2):键值对最多 10 对,键和值均不可为 null;键重复直接编译/运行时报错
- 超限情况用 Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2)) 或 List.ofEntries()(Java 21+)
避免用 Collections.unmodifiableXxx() 包装已有可变集合
这个方法只加了一层“只读外壳”,底层集合一旦被修改,不可变视图立刻同步变化——它不是数据保护,只是操作拦截。
- 如果必须用 unmodifiable,先做浅拷贝:new ArrayList(originalList) 再套 Collections.unmodifiableList()
- 对于 Map,同样要先 new HashMap(originalMap),否则 unmodifiableMap() 形同虚设
- 注意:这些拷贝只到第一层,若集合里存的是 ArrayList 或自定义对象,它们内部仍可变
泛型类中安全初始化和封装内部集合
在泛型类里操作集合,类型安全要贯穿始终,不能只靠初始化“一次到位”。
立即学习“Java免费学习笔记(深入)”;
- 构造器中初始化推荐 list = new ArrayList<>();,后续所有 add 方法只接收泛型参数 T item,让编译器拦住非法类型
- 对外提供集合访问时,绝不返回原始 list 引用;改用 Collections.unmodifiableList(list) 或直接返回 List.of(list.toArray())(Java 9+)
- 如果需要真正隔离,且 list 已存在,可用 List.copyOf(list)(Java 10+),它会复制并返回不可变视图,且自动处理 null 检查
警惕常见陷阱
有些写法看似简洁,实则埋下隐患。
- Arrays.asList("a", "b") 返回的是私有静态内部类,不支持 add/remove,但它是可变数组的视图,且没有线程安全保证
- 双大括号初始化 new ArrayList<>() {{ add("x"); }} 会生成匿名子类,持有外部类引用,容易导致内存泄漏
- unmodifiableSet(new ArrayList(Arrays.asList("a", "a"))) 不会去重,size() 和 contains() 行为不一致;应先用 new HashSet<>(list) 或 Set.copyOf(list)


















