本文目录导读:

Java 集合工厂方法(List.of()、Set.of()、Map.of() 等,Java 9+)非常好用,尤其适用于创建不可变、元素数量固定的集合,从工程实践角度看,它们能显著提升代码的简洁性、安全性和性能。
下面从几个核心维度帮你分析,方便你判断在什么场景下使用:
核心优点
-
极致的简洁与可读性
- 传统方式:
List<String> list = new ArrayList<>(); list.add("a"); list.add("b");或Arrays.asList("a", "b")。 - 工厂方式:
List<String> list = List.of("a", "b");。 - 尤其适合构造测试数据、常量集合或临时集合,代码一目了然。
- 传统方式:
-
完全的不可变性
- 创建的集合是不可变的,不能调用
add、remove、set等方法,否则会抛出UnsupportedOperationException。 - 这是最大的价值之一,在多线程环境下,无需考虑同步问题;在 API 设计中,返回这种集合可以安全地确保调用方不会意外修改内部数据。
- 创建的集合是不可变的,不能调用
-
自动防御性拷贝
- 相比
Arrays.asList()返回的“可修改的视图”,工厂方法创建的集合不依赖原数组,如果你需要返回一个内部数据结构的快照,return List.of(...)比手动new ArrayList<>(internalList)更简洁且能防止外部修改。
- 相比
-
性能与内存优化
- JDK 内部针对
of()方法有专门优化。List.of()对于 0 个、1 个、2 个元素等,会返回不同的、经过高度特化的内部类(如ListN、List12),通常比通用的ArrayList或Arrays.asList更节省内存。
- JDK 内部针对
-
元素校验
- 工厂方法不接受
null元素,如果你传入null,会立刻抛出NullPointerException,这能帮助你在代码早期就发现潜在的空指针问题,避免数据进入深层逻辑后出问题。
- 工厂方法不接受
常见陷阱与注意事项
-
禁止 null 元素
- 这是最大的限制,如果你的集合逻辑上允许
null,则不能使用工厂方法,需要退回到new ArrayList<>()或new HashSet<>()。
- 这是最大的限制,如果你的集合逻辑上允许
-
不支持加、删、改操作
- 如果你在后续代码中需要修改集合(例如添加日志、条件过滤),不能使用工厂方法,你需要将其复制到一个可变集合中:
var immutableList = List.of("a", "b"); var mutableList = new ArrayList<>(immutableList); // 或 List.copyOf() 的逆操作
- 如果你在后续代码中需要修改集合(例如添加日志、条件过滤),不能使用工厂方法,你需要将其复制到一个可变集合中:
-
Map.of() 的限制(Java 9-8)
Map.of()最多只支持 10 个键值对(Map.of(k1,v1, k2,v2, ..., k10,v10)),超过 10 个键值对,需要改用Map.ofEntries(),写法稍复杂:Map.ofEntries( Map.entry("key1", "val1"), Map.entry("key2", "val2"), // ... 不限数量 );
-
只读 ≠ 深度不可变
- 工厂方法保证的是集合结构的不可变(不能增删元素),但如果元素本身是可变对象(如
Date、ArrayList或内部有setter的自定义类),你仍然可以修改这些对象的状态,它提供的是“浅层”不可变。
- 工厂方法保证的是集合结构的不可变(不能增删元素),但如果元素本身是可变对象(如
与 Arrays.asList() 的关键区别
| 特性 | List.of() |
Arrays.asList() |
new ArrayList<>() |
|---|---|---|---|
| 大小 | 不可变 | 固定大小 | 可变大小 |
| 修改操作 | 不支持 set、add、remove |
支持 set,不支持 add/remove |
全部支持 |
| Null 支持 | 不支持 | 支持 | 支持 |
| 底层实现 | 工厂内部类 | 数组视图 | 动态数组 |
| 与数组的关系 | 独立 | 共享底层数组 | 独立 |
| 使用场景 | 常量、枚举、安全返回、函数式 | 遗留代码、需要 set 操作的场景 |
大部分通用场景 |
最佳实践建议
- 强推荐:定义常量集合时,优先使用
List.of()/Set.of()/Map.of()。 - 强推荐:在 API 中返回一个内部集合时,使用
Collections.unmodifiableList(...)或List.copyOf()。List.copyOf()内部会调用工厂方法,效果一致。 - 推荐:在测试代码中大量使用,快速构造测试数据。
- 谨慎使用:在编写函数式/流式操作时,可以用它对现有流进行过滤、转换后生成不可变结果:
var result = stream.filter(...).collect(Collectors.toUnmodifiableList());
- 考虑替代方案:如果需要可变、允许 null、或超过 10 对的
Map,用new HashMap<>()更合适;如果需要更大的灵活性和易用性(如 Guava 的ImmutableList、Maps.newHashMap()等),第三方库(如 Guava)提供了类似但更丰富的功能,Guava 的不可变集合语义更严格(ImmutableList.of()同样不允许 null)。
非常好用,但需要明确其不可变和无 null 的契约。
- 优点:简洁、安全(不可变、拒绝 null)、性能佳。
- 缺点:不可变、无 null、Map 键值对有限制。
只要你的场景符合“构造后就不变”这一条件(这在实际开发中比想象中更多),就放心大胆地用,它带来的代码清晰度和安全性提升非常明显,已在 Java 社区成为主流写法。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播