List.of
、Set.of
、Map.of
创建安全不可变集合Java 9引入了革命性的集合工厂方法List.of
、Set.of
和Map.of
,彻底改变了开发者创建小型不可变集合的方式。这些方法不仅语法简洁,还在安全性和性能上实现了质的飞跃。本文将深入解析这些工厂方法的核心特性,并通过对比传统方式,展示其在实际开发中的优势。
方法签名 | 说明 | 示例 |
---|---|---|
List.of(E... elements) |
创建不可变List | List |
Set.of(E... elements) |
创建不可变Set(元素唯一) | Set |
Map.of(K k1, V v1, ...) |
创建不可变Map(最多10个键值对) | Map |
Map.ofEntries(Map.Entry...) |
创建任意数量键值对的Map | Map.ofEntries(entry("a", 1), entry("b", 2)) |
传统方式的问题:
// Java 8的"不可变"集合
List<String> oldList = Collections.unmodifiableList(
new ArrayList<>(Arrays.asList("A", "B"))
);
oldList.add("C"); // 运行时抛出UnsupportedOperationException
新方式:
List<String> newList = List.of("A", "B");
newList.add("C"); // 编译期即可通过IDE提示发现问题
特性 | 新工厂方法 | Collections.unmodifiableList |
---|---|---|
编译期类型检查 | ✅ 直接拒绝修改操作 | ❌ 运行时异常 |
防御原集合修改 | ✅ 完全独立 | ❌ 包装集合仍受原集合影响 |
List.of("A", null); // 立即抛出NullPointerException
Set.of(null); // 同上
Map.of("key", null);// 值也不能为null
设计哲学:在集合创建时严格拒绝null
,避免后续NPE隐患。
Set.of(1, 1); // 直接抛出IllegalArgumentException
Map.of("a", 1, "a", 2); // 键重复,抛出异常
JVM针对工厂方法返回的集合做了深度优化:
new ArrayList
节省约30%内存Set.of
/Map.of
在创建时预计算哈希值Java 8方式:
List<String> list = Collections.unmodifiableList(
new ArrayList<>(Arrays.asList("A", "B"))
);
// 需要两层包装,内存开销大
Java 9方式:
List<String> list = List.of("A", "B");
// 直接返回优化后的不可变实例
传统方式:
Set<Integer> set = Collections.unmodifiableSet(
new HashSet<>(Arrays.asList(1, 2, 3))
);
// 无法保证初始化时的元素唯一性
新方式:
Set<Integer> set = Set.of(1, 2, 3);
// 自动检查元素唯一性,发现重复立即报错
传统方式:
Map<String, Integer> tempMap = new HashMap<>();
tempMap.put("a", 1);
tempMap.put("b", 2);
Map<String, Integer> map = Collections.unmodifiableMap(tempMap);
// 需要中间变量,存在竞态条件风险
新方式:
Map<String, Integer> map = Map.of("a", 1, "b", 2);
// 线程安全,无中间状态
Map.of
最多接受10个键值对(超过需用Map.ofEntries
)List.of(1, 2, 3); // 正确:自动装箱
List.of(new int[]{1}); // 错误:实际类型为List
// 接收外部集合时创建防御副本
void process(List<String> input) {
List<String> safeList = List.copyOf(input); // Java 10+
// 或 List safeList = List.of(input.toArray());
}
// 过滤后生成不可变集合
List<String> filtered = Stream.of("A", "B", "C")
.filter(s -> s.length() > 1)
.collect(Collectors.toUnmodifiableList());
private static final Set<String> VALID_STATUSES =
Set.of("NEW", "PROCESSING", "COMPLETED");
@Test
void testSort() {
List<Integer> numbers = List.of(3, 1, 4);
Collections.sort(numbers); // 立即抛出UnsupportedOperationException
}
public List<Employee> getEmployees() {
return List.copyOf(internalList); // 返回不可变副本
}
List<String> emptyList = List.of(); // 空集合单例
Set<Integer> emptySet = Set.of();
Map<String, String> emptyMap = Map.of();
Arrays.asList
的区别?特性 | List.of |
Arrays.asList |
---|---|---|
可变性 | 完全不可变 | 半可变(可set不可add) |
空值支持 | ❌ 禁止null | ✅ 允许null |
与原数组关联 | ❌ 独立存储 | ✅ 共享底层数组 |
内存占用 | 优化后的紧凑结构 | 包装器+数组引用 |
使用新工厂方法的三大理由:
适用原则:
迁移建议:
Collections.unmodifiableXXX
的用法null
值使用Java 9的集合工厂方法不仅是语法糖,更是工程实践的重要进步。合理运用这些特性,可以让代码更健壮、更高效,同时降低维护成本。