在Java中,不可变集合指的是创建完成后,其内部元素的数量、每个元素的值都无法被修改的集合类型,属于Java集合只读设计的重要实现形式。它和普通的通过工具类生成的只读集合有本质区别,适用场景也更广泛。

不可变集合的核心特性
不可变集合具备三个核心特性,这也是它和普通集合最明显的差异:
- 不可修改元素:无法通过集合的add、remove、set等方法修改集合内容,调用这些方法会直接抛出UnsupportedOperationException异常。
- 不可替换元素:即使集合中的元素本身是可变对象,集合本身也不会提供修改元素引用的途径,不过如果元素是可变对象,修改对象内部属性不属于集合层面的修改。
- 线程安全:由于内容不可变,多线程环境下不需要额外加锁就可以安全共享,不会出现并发修改导致的异常。
Java中创建不可变集合的常见方式
1. 使用Collections工具类的unmodifiable方法
这是Java早期版本就提供的创建只读集合的方式,不过这种方式生成的集合并不是严格意义上的不可变集合,它只是对原集合做了一个包装,原集合如果被修改,包装后的集合内容也会跟着变化。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class UnmodifiableDemo {
public static void main(String[] args) {
// 创建原始可变集合
List<String> originalList = new ArrayList<>();
originalList.add("a");
originalList.add("b");
// 生成只读包装集合
List<String> readOnlyList = Collections.unmodifiableList(originalList);
// 调用修改方法会抛出异常
// readOnlyList.add("c"); // 这行代码会抛出UnsupportedOperationException
// 修改原始集合,只读集合内容会同步变化
originalList.add("c");
System.out.println(readOnlyList); // 输出 [a, b, c]
}
}
2. Java 9+的工厂方法创建不可变集合
Java 9之后,在List、Set、Map接口中新增了of方法,可以直接创建严格意义上的不可变集合,这种方式创建的集合完全不可变,和原始数据没有任何关联。
import java.util.List;
import java.util.Set;
import java.util.Map;
public class ImmutableFactoryDemo {
public static void main(String[] args) {
// 创建不可变List
List<String> immutableList = List.of("x", "y", "z");
// 创建不可变Set
Set<Integer> immutableSet = Set.of(1, 2, 3);
// 创建不可变Map
Map<String, Integer> immutableMap = Map.of("key1", 1, "key2", 2);
// 所有修改操作都会抛出异常
// immutableList.add("w"); // 抛出UnsupportedOperationException
// immutableSet.remove(1); // 抛出UnsupportedOperationException
// immutableMap.put("key3", 3); // 抛出UnsupportedOperationException
}
}
3. 使用Guava等第三方库的不可变集合
如果使用的是Java 8及更早版本,也可以使用Guava库提供的不可变集合类,比如ImmutableList、ImmutableSet等,功能和Java 9+的工厂方法类似。
import com.google.common.collect.ImmutableList;
public class GuavaImmutableDemo {
public static void main(String[] args) {
// 使用Guava创建不可变List
ImmutableList<String> guavaList = ImmutableList.of("m", "n");
// 也可以通过builder构建
ImmutableList<String> guavaList2 = ImmutableList.<String>builder()
.add("p")
.add("q")
.build();
// 修改操作会抛出异常
// guavaList.add("o"); // 抛出UnsupportedOperationException
}
}
不可变集合与只读集合的区别
很多开发者会混淆不可变集合和只读集合的概念,两者的核心差异如下:
| 对比维度 | 不可变集合 | 只读集合(Collections.unmodifiable包装) |
|---|---|---|
| 内容是否可修改 | 完全不可修改,创建后内容固定 | 本身不能修改,但原始集合修改会影响它 |
| 线程安全性 | 绝对线程安全,无需额外处理 | 如果原始集合被多线程修改,仍有线程安全问题 |
| 适用场景 | 常量集合、多线程共享数据、防御性拷贝 | 临时限制集合修改权限的场景 |
不可变集合的适用场景
不可变集合在以下场景中能发挥很大作用:
- 定义常量集合:比如系统中固定的状态码列表、配置项集合,使用不可变集合可以避免被意外修改。
- 多线程共享数据:不需要加锁就可以在多个线程之间传递集合,减少同步开销。
- 防御性拷贝:当方法需要返回一个内部集合时,返回不可变集合可以避免外部代码修改内部数据,提升代码安全性。
- 函数式编程场景:不可变集合符合函数式编程的无副作用特性,适合在流式计算中使用。
注意事项
使用不可变集合时需要注意两个点:
- 如果集合中的元素是可变对象,比如自定义的类实例,修改对象本身的属性并不会触发集合的修改异常,但是这不符合不可变集合的设计初衷,建议不可变集合中存储不可变对象,比如String、基本类型的包装类。
- Java 9+的List.of、Set.of、Map.of方法创建的集合不支持存储null元素,如果尝试添加null会直接抛出NullPointerException,而Collections.unmodifiable包装的集合是否支持null取决于原始集合。
Java不可变集合只读集合CollectionsList_of修改时间:2026-07-12 13:36:29