深度解析 Collectors.toMap 和 collect 方法

一、collect 方法详解

1. 核心功能

collect() 是 Java Stream API 的终端操作,用于将流中的元素累积到可变容器(如集合、Map)中。它提供了两种形式:

// 基础形式
<R> R collect(Supplier<R> supplier,
              BiConsumer<R, ? super T> accumulator,
              BiConsumer<R, R> combiner);

// 常用形式(使用Collector)
<R, A> R collect(Collector<? super T, A, R> collector);

2. 核心组件

当使用 Collector 时,包含三个关键组件:

  • Supplier:创建结果容器的工厂

  • Accumulator:将元素添加到容器的函数

  • Combiner:合并并行流结果的函数(用于并行处理)

3. 工作原理

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 手动实现collect
List<String> result = names.stream().collect(
    ArrayList::new,       // Supplier: 创建容器
    ArrayList::add,       // Accumulator: 添加元素
    ArrayList::addAll     // Combiner: 合并结果
);

// 等价于
List<String> result = names.stream().collect(Collectors.toList());

二、Collectors.toMap 深度解析

1. 方法签名

// 基本形式
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
    Function<? super T, ? extends K> keyMapper,
    Function<? super T, ? extends U> valueMapper)

// 完整形式
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)

2. 参数详解

参数类型说明示例
keyMapperFunction<T, K>从元素提取键的函数AttributePair::getKey
valueMapperFunction<T, U>从元素提取值的函数AttributePair::getValue
mergeFunctionBinaryOperator<U>键冲突时合并值的策略(v1, v2) -> v2
mapSupplierSupplier<M>指定Map实现类的工厂TreeMap::new

3. 使用场景示例

场景1:基本转换
List<AttributePair> pairs = Arrays.asList(
    new AttributePair("color", "red"),
    new AttributePair("size", "L")
);

Map<String, String> map = pairs.stream()
    .collect(Collectors.toMap(
        AttributePair::getKey,
        AttributePair::getValue
    ));
// 结果: {color=red, size=L}
场景2:处理键冲突
List<AttributePair> pairs = Arrays.asList(
    new AttributePair("color", "red"),
    new AttributePair("color", "blue") // 重复键
);

// 保留最新值
Map<String, String> map1 = pairs.stream()
    .collect(Collectors.toMap(
        AttributePair::getKey,
        AttributePair::getValue,
        (oldVal, newVal) -> newVal
    ));
// 结果: {color=blue}

// 合并值
Map<String, String> map2 = pairs.stream()
    .collect(Collectors.toMap(
        AttributePair::getKey,
        AttributePair::getValue,
        (v1, v2) -> v1 + "," + v2
    ));
// 结果: {color=red,blue}
场景3:指定Map实现
// 使用TreeMap按键排序
Map<String, String> sortedMap = pairs.stream()
    .collect(Collectors.toMap(
        AttributePair::getKey,
        AttributePair::getValue,
        (v1, v2) -> v2,
        TreeMap::new
    ));

4. 实现原理(简化版)

public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
    Function<? super T, ? extends K> keyMapper,
    Function<? super T, ? extends U> valueMapper) {
    
    return Collector.of(
        HashMap::new, // Supplier
        (map, element) -> {
            K key = keyMapper.apply(element);
            U value = valueMapper.apply(element);
            if (map.putIfAbsent(key, value) != null) {
                throw new IllegalStateException("Duplicate key");
            }
        },
        (map1, map2) -> {
            map1.putAll(map2);
            return map1;
        }
    );
}

5. 关键注意事项

  1. 键冲突处理

    • 默认情况下,遇到重复键会抛出 IllegalStateException

    • 必须提供 mergeFunction 解决冲突

  2. 空值问题

    • 键不能为 null(会抛出 NullPointerException

    • 值可以为 null,但取决于具体 Map 实现

  3. 并行流支持

    Map<String, String> parallelMap = pairs.parallelStream()
        .collect(Collectors.toMap(
            AttributePair::getKey,
            AttributePair::getValue,
            (v1, v2) -> v2
        ));

  4. 性能优化

    • 大集合使用 ConcurrentHashMap 提高并行性能

    Map<String, String> concurrentMap = pairs.parallelStream()
        .collect(Collectors.toMap(
            AttributePair::getKey,
            AttributePair::getValue,
            (v1, v2) -> v2,
            ConcurrentHashMap::new
        ));

三、高级应用技巧

1. 嵌套映射

// 创建多级Map
Map<String, Map<String, String>> nestedMap = products.stream()
    .collect(Collectors.toMap(
        Product::getCategory,
        p -> Map.of("name", p.getName(), "price", p.getPrice()),
        (map1, map2) -> {
            map1.putAll(map2);
            return map1;
        },
        TreeMap::new
    ));

2. 复杂对象转换

// 值转换为复杂对象
Map<Long, ProductSummary> summaryMap = products.stream()
    .collect(Collectors.toMap(
        Product::getId,
        p -> new ProductSummary(p.getName(), p.getPrice()),
        (s1, s2) -> s1 // 处理冲突
    ));

3. 不可变Map

// Java 10+ 创建不可变Map
Map<String, String> immutableMap = pairs.stream()
    .collect(Collectors.toUnmodifiableMap(
        AttributePair::getKey,
        AttributePair::getValue,
        (v1, v2) -> v1 // 冲突处理
    ));

4. 分组统计

// 按类别分组并统计数量
Map<String, Long> categoryCount = products.stream()
    .collect(Collectors.groupingBy(
        Product::getCategory,
        Collectors.counting()
    ));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值