Collectors.toMap

Collectors.toMap 是 Java 8 引入的用于将流(Stream)中的元素收集到 Map 中的收集器(Collector)。它有多个重载版本,其中 四个参数的版本 是最完整、最灵活的一种:

public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(
    Function<? super T, ? extends K> keyMapper,
    Function<? super T, ? extends U> valueMapper,
    BinaryOperator<U> mergeFunction,
    Supplier<M> mapSupplier
)

四个参数详解:

  1. keyMapper

    • 类型:Function<? super T, ? extends K>
    • 作用:将流中的每个元素 T 映射为 Map 的键(K)。
    • 示例:Person::getName(假设流中是 Person 对象,用名字做 key)
  2. valueMapper

    • 类型:Function<? super T, ? extends U>
    • 作用:将流中的每个元素 T 映射为 Map 的值(U)。
    • 示例:Person::getAge(用年龄做 value)
  3. mergeFunction

    • 类型:BinaryOperator<U>(即 (U, U) -> U
    • 作用:当出现重复键时,如何合并两个值。这是解决键冲突的关键。
    • 示例:(oldValue, newValue) -> oldValue(保留旧值)或 (v1, v2) -> v1 + v2(合并数值)
  4. mapSupplier

    • 类型:Supplier<M>(返回一个空的 Map 实例)
    • 作用:指定要创建的 Map 类型(如 HashMapLinkedHashMapTreeMap 等)。
    • 示例:LinkedHashMap::new(保持插入顺序)

使用示例

假设有如下 Person 类:

class Person {
    String name;
    int age;
    // 构造函数、getter 省略
}

示例 1:基本用法(带冲突处理和指定 Map 类型)

List<Person> people = Arrays.asList(
    new Person("Alice", 30),
    new Person("Bob", 25),
    new Person("Alice", 35) // 重复 key "Alice"
);

Map<String, Integer> nameToAge = people.stream()
    .collect(Collectors.toMap(
        Person::getName,                    // keyMapper
        Person::getAge,                     // valueMapper
        (age1, age2) -> age1,               // mergeFunction: 保留第一个
        LinkedHashMap::new                  // mapSupplier: 保持插入顺序
    ));

结果:

{Alice=30, Bob=25}

示例 2:合并值(如累加)

Map<String, Integer> nameToTotalAge = people.stream()
    .collect(Collectors.toMap(
        Person::getName,
        Person::getAge,
        Integer::sum,            // 合并时相加
        HashMap::new
    ));

结果:

{Alice=65, Bob=25}

示例 3:使用 TreeMap(按键排序)

Map<String, Integer> sortedMap = people.stream()
    .collect(Collectors.toMap(
        Person::getName,
        Person::getAge,
        (v1, v2) -> v1,
        TreeMap::new
    ));

注意事项

  • 如果不提供 mergeFunction(即使用三参数版本),遇到重复键会抛出 IllegalStateException
  • mapSupplier 允许你控制 Map 的具体实现,对性能或顺序有要求时非常有用。
  • 所有函数参数都不能为 null,否则会抛出 NullPointerException

总结

四参数 Collectors.toMap 提供了完整的控制能力:

  • 如何生成 key
  • 如何生成 value
  • 如何处理 key 冲突
  • 使用哪种 Map 实现

适用于各种复杂场景,是流式处理中构建 Map 的强大工具。

posted @ 2025-11-17 20:02  chuangzhou  阅读(154)  评论(0)    收藏  举报