不可变集合能防止意外修改导致的并发问题:其构造后禁止写操作,杜绝竞态条件;底层无同步开销,读性能更优;具备可传递不可变性;Guava的copyOf()深拷贝并冻结,而Arrays.asList()仅为视图;Java 9+ List.of()有null和数量限制;unmodifiableXXX()仅为只读包装,非真正不可变。

不可变集合能防止意外修改导致的并发问题
多线程环境下,ArrayList 或 HashMap 被多个线程共享时,即使只读操作也容易因结构变更(如扩容、rehash)引发 ConcurrentModificationException 或数据不一致。不可变集合(如 ImmutableList、ImmutableSet)在构造后彻底禁止写操作,从根源上消除竞态条件。
- 调用
add()、remove()等方法会直接抛出UnsupportedOperationException,而非静默失败 - 底层数据结构通常使用紧凑数组或 trie,无同步开销,读性能优于
Collections.synchronizedList() - 不可变性可传递:若集合元素本身也是不可变对象(如
String、LocalDateTime),整个数据结构就具备强一致性保证
Guava 的 ImmutableList.copyOf() 和 Arrays.asList() 行为完全不同
Arrays.asList() 返回的是“视图”——它包装原始数组,修改返回列表会直接影响原数组;而 ImmutableList.copyOf() 会深拷贝元素并冻结结构。
String[] arr = {"a", "b"};
List view = Arrays.asList(arr);
view.set(0, "x"); // arr[0] 变成 "x"
List imm = ImmutableList.copyOf(arr);
imm.set(0, "x"); // 抛出 UnsupportedOperationException
arr[0] = "y"; // 不影响 imm
- 注意:如果传入的是
null,copyOf()会立即抛出NullPointerException;而Arrays.asList(null)会创建含一个null元素的列表 - 对已有集合调用
copyOf()时,仍会遍历并复制所有元素,不复用原集合内部结构
Java 9+ 内置 List.of() 有严格限制,不是万能替代
List.of()、Set.of()、Map.of() 是轻量级不可变工厂方法,但设计目标是常量初始化场景,不是通用容器。
- 不接受
null元素:传入null会直接抛出NullPointerException - 最大元素数受限:
List.of()最多支持 10 个参数(List.of(a,b,c...j)),超过需用List.ofArray()或 Guava - 空集合必须显式调用
List.of(),不能靠of()推断;且返回实例不保证跨调用相等(即List.of() == List.of()为false)
误用 unmodifiableXXX() 容易产生“假不可变”陷阱
Collections.unmodifiableList() 等方法只是加了一层只读包装,**原始集合一旦被修改,不可变视图也会随之变化**——这不是真正不可变。
立即学习“Java免费学习笔记(深入)”;
Listoriginal = new ArrayList<>(Arrays.asList("a", "b")); List unmod = Collections.unmodifiableList(original); original.add("c"); // unmod.size() 现在也变成 3!
- 这种包装类无法防御底层集合被其他引用修改,仅防误调用,不防并发或逻辑错误
- 若需安全共享,必须确保原始集合不再有其他可变引用,否则应改用
ImmutableList.copyOf()或List.of() - 调试时遇到“只读集合内容却变了”,第一反应应检查是否混用了
unmodifiableXXX()和原始可变引用










