Collections.singleton 返回不可变集合,因其内部是轻量级不可变视图,不封装新容器而仅返回固定引用,调用 add/remove 等修改方法会抛 UnsupportedOperationException。

为什么 Collections.singleton 返回的是不可变集合?
因为它本质是内部实现的轻量级不可变视图,不封装新容器,只返回一个固定引用。这带来性能优势,但也意味着你不能调用 add、remove 或任何修改方法——否则直接抛 UnsupportedOperationException。
常见错误现象:Collection<string> s = Collections.singleton("a"); s.add("b");</string> 运行时报错,不是编译报错,容易在运行时才暴露。
- 适用场景:函数参数需要传入“确定只有一个元素”的集合(比如作为默认值、测试桩、配置项兜底)
- 它返回的是
Set,不是List;如果要单元素List,得用Collections.singletonList - 注意:返回对象是线程安全的,但“安全”仅指不可变,不是并发工具类
Collections.nCopies 的坑:修改副本会连锁影响所有元素?
是的——Collections.nCopies(3, new ArrayList()) 看似创建了三个空列表,实际只创建了一个实例,其余是引用共享。后续对任一元素的修改(如 get(0).add("x")),get(1) 和 get(2) 也会看到这个变化。
根本原因:它返回的是懒加载的不可变视图,内部用单一对象重复映射索引,不做深拷贝。
立即学习“Java免费学习笔记(深入)”;
- 正确做法:需要独立副本时,必须显式复制,例如
Stream.generate(ArrayList::new).limit(3).collect(Collectors.toList()) - 适合场景:只读用途,比如初始化默认值数组、填充日志模板、做
contains判断 - 性能友好:内存占用极小,O(1) 创建,但误当可变集合用会导致隐蔽 bug
singletonList / singletonSet / singletonMap —— 三者命名规则与行为差异
它们都属于 Collections 工具类的“单例集合工厂”,但返回类型和契约不同,不能混用。
-
Collections.singletonList("x")→ 返回List,允许get(0),但禁止set(0, ...)(同样抛UnsupportedOperationException) -
Collections.singleton("x")→ 返回Set,无序,且自动去重(当然单个元素无所谓) -
Collections.singletonMap("k", "v")→ 返回Map,键值对唯一,也不支持put或remove
关键区别不在功能,而在语义:API 调用方依赖返回类型做后续操作(比如传给只接受 List 的方法),类型错了编译就过不去。
替代方案:什么时候该放弃 nCopies 改用 Arrays.asList 或构造器?
当你需要可变副本、或元素本身是可变对象(如 new Date()、new HashMap())时,nCopies 就不该出现。
例如:Collections.nCopies(2, new Date()) 返回两个指向同一时刻的引用,毫秒级时间戳完全一样;而 Arrays.asList(new Date(), new Date()) 才真正生成两个独立实例。
- 若元素是基本类型包装类(
Integer、String)且只读,nCopies安全又省事 - 若需后续修改任意一项,优先用
Stream.generate(() -> new T()).limit(n).collect(...) - Java 10+ 可考虑
List.of/Set.of,但注意它们也是不可变的,且不接受 null
最常被忽略的一点:这些工具方法返回的集合都不支持 null 元素(除了 singletonList 允许 null 值),传进去不会立即报错,但某些操作(如序列化、Hibernate 映射)可能中途崩溃。










