集合工厂方法
写代码时,你一定经常这样创建小集合:
java
// 以前的方式
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
// 稍微好一点
List<String> list = Arrays.asList("a", "b", "c");JDK 9 之前,Arrays.asList 已经是比较简洁的方式了。但它有个问题:返回的 List 是可变的,但不支持增删操作。
JDK 9 引入了集合工厂方法,让创建小型不可变集合变得优雅。
四种工厂方法
java
// List.of()
List<String> list = List.of("a", "b", "c");
// Set.of()
Set<Integer> set = Set.of(1, 2, 3);
// Map.of()
Map<String, Integer> map = Map.of(
"a", 1,
"b", 2,
"c", 3
);
// Map.ofEntries() - 超过 10 个键值对时用
Map<String, Integer> bigMap = Map.ofEntries(
Map.entry("a", 1),
Map.entry("b", 2),
Map.entry("c", 3),
Map.entry("d", 4)
);与 Arrays.asList 对比
java
import java.util.*;
public class FactoryMethodCompare {
public static void main(String[] args) {
// Arrays.asList:底层是固定大小的数组
List<String> asList = Arrays.asList("a", "b", "c");
// ✅ 可以修改元素
asList.set(0, "x");
System.out.println(asList); // [x, b, c]
// ❌ 不能增删元素
// asList.add("d"); // UnsupportedOperationException
// asList.remove(0); // UnsupportedOperationException
System.out.println("=== List.of ===");
// List.of:真正的不可变集合
List<String> listOf = List.of("a", "b", "c");
// ❌ 所有修改操作都抛异常
// listOf.set(0, "x"); // UnsupportedOperationException
// listOf.add("d"); // UnsupportedOperationException
System.out.println("listOf = " + listOf);
}
}| 操作 | Arrays.asList | List.of |
|---|---|---|
set(index, value) | ✅ 支持 | ❌ 抛异常 |
add(element) | ❌ 抛异常 | ❌ 抛异常 |
remove(index) | ❌ 抛异常 | ❌ 抛异常 |
clear() | ❌ 抛异常 | ❌ 抛异常 |
null 元素 | ✅ 允许 | ❌ 不允许 |
| 重复元素 | ✅ 允许 | ❌ Set/Map 不允许 |
详细用法
List.of
java
// 空 List
List<String> empty = List.of();
// 单元素
List<String> one = List.of("a");
// 多个元素
List<String> multi = List.of("a", "b", "c", "d", "e");
// 可以放任何类型
List<Object> mixed = List.of("string", 123, List.of(1, 2, 3));
// 不允许 null
// List.of(null); // NullPointerExceptionSet.of
java
// 空 Set
Set<Integer> empty = Set.of();
// 单元素
Set<Integer> one = Set.of(1);
// 多个元素
Set<Integer> multi = Set.of(1, 2, 3);
// 不允许重复(Set 的特性)
// Set.of(1, 1, 2); // IllegalArgumentException: duplicate element: 1Map.of / Map.ofEntries
java
// 空 Map
Map<String, Integer> empty = Map.of();
// 单个键值对
Map<String, Integer> one = Map.of("a", 1);
// 多个键值对(最多 10 个)
Map<String, Integer> multi = Map.of(
"a", 1,
"b", 2,
"c", 3
);
// 超过 10 个用 ofEntries
Map<String, Integer> big = Map.ofEntries(
Map.entry("a", 1),
Map.entry("b", 2),
Map.entry("c", 3),
Map.entry("d", 4),
Map.entry("e", 5),
Map.entry("f", 6),
Map.entry("g", 7),
Map.entry("h", 8),
Map.entry("i", 9),
Map.entry("j", 10),
Map.entry("k", 11) // 超过 10 个只能用 ofEntries
);
// Map.entry 快捷方式(JDK 9+)
Map.Entry<String, Integer> entry = Map.entry("key", 1);常见使用场景
场景一:方法返回固定集合
java
// ❌ 以前:返回后还能修改(不安全)
public List<String> getSupportedLanguages() {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
return list; // 调用者可以修改
}
// ✅ 现在:返回不可变集合
public List<String> getSupportedLanguages() {
return List.of("Java", "Python", "JavaScript");
}
// ✅ 调用者想改也改不了
List<String> langs = getSupportedLanguages();
langs.add("Go"); // UnsupportedOperationException场景二:Switch 表达式(JDK 14+)
java
public String getDayType(String day) {
return switch (day) {
case "SATURDAY", "SUNDAY" -> "周末";
case "MONDAY", "TUESDAY", "WEDNESDAY",
"THURSDAY", "FRIDAY" -> "工作日";
default -> {
Set<String> validDays = Set.of(
"MONDAY", "TUESDAY", "WEDNESDAY",
"THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"
);
if (!validDays.contains(day)) {
yield "无效日期";
}
yield "未知";
}
};
}场景三:常量映射
java
// HTTP 状态码
Map<Integer, String> HTTP_STATUS = Map.of(
200, "OK",
201, "Created",
400, "Bad Request",
401, "Unauthorized",
403, "Forbidden",
404, "Not Found",
500, "Internal Server Error"
);
// 查找
String message = HTTP_STATUS.getOrDefault(404, "Unknown");场景四:Stream 的数据源
java
// 快速构建测试数据
List<Person> people = List.of(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 35)
);
// Stream 处理
people.stream()
.filter(p -> p.getAge() > 30)
.forEach(System.out::println);注意事项
不允许 null
java
// ❌ 全部抛 NullPointerException
List.of(null);
Set.of(null);
Map.of("key", null); // value 是 null 也不行
Map.of(null, 1); // key 是 null 也不行Set/Map 不允许重复
java
// ❌ 抛 IllegalArgumentException
Set.of(1, 2, 2, 3); // 2 重复了
// ❌ 抛 IllegalArgumentException
Map.of("a", 1, "a", 2); // key "a" 重复了不是 Serializable
java
List<String> list = List.of("a", "b");
// ❌ 默认不支持序列化
// byte[] bytes = serialize(list);
// ✅ 需要序列化时用
List<String> serializable = Collections.unmodifiableList(
new ArrayList<>(List.of("a", "b"))
);
// 或者自己实现序列化
public class ImmutableList<T> extends AbstractList<T>
implements Serializable {
// ...
}性能特点
工厂方法创建的集合有以下特点:
| 特点 | 说明 |
|---|---|
| 不可变 | 任何修改操作都抛异常 |
| 线程安全 | 不需要同步 |
| 内存优化 | 内部使用特殊实现,比 ArrayList/HashMap 省内存 |
| 不支持序列化 | 需要自己处理(JDK 16+ List.copyOf 是 Serializable) |
小结
工厂方法让创建小集合变得优雅:
java
// ✅ 推荐
List<String> list = List.of("a", "b", "c");
Set<Integer> set = Set.of(1, 2, 3);
Map<String, Integer> map = Map.of("a", 1, "b", 2);
// ❌ 不推荐
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");记住三个选择原则:
- 需要修改 → 用
new ArrayList<>(...)或Arrays.asList() - 返回固定数据 → 用
List.of() - Set/Map 小集合 → 用
Set.of()/Map.of()
