Skip to content

集合工厂方法

写代码时,你一定经常这样创建小集合:

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.asListList.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);  // NullPointerException

Set.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: 1

Map.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");

记住三个选择原则:

  1. 需要修改 → 用 new ArrayList<>(...)Arrays.asList()
  2. 返回固定数据 → 用 List.of()
  3. Set/Map 小集合 → 用 Set.of() / Map.of()

基于 VitePress 构建