Collectors.toMap的使用

Collectors.toMap 是 Java Stream API 中的一个非常有用的收集器(Collector),它允许你将流(Stream)中的元素收集到一个 Map 中。你需要指定如何从每个流元素中提取键(key)和值(value),以及如何处理键冲突(如果有的话)

以下是 Collectors.toMap 的一些基本用法:

1. 基本的键和值映射

当你确信流中的元素不会产生键冲突时,你可以简单地指定键和值的映射函数:

import java.util.List;  
import java.util.Map;  
import java.util.stream.Collectors;  
  
// 假设FarmersCountVO是一个类,它有一个getCode()方法和一个getName()方法  
List<FarmersCountVO> farmerList = ...; // 农民列表  
  
Map<String, String> farmerMap = farmerList.stream()  
    .collect(Collectors.toMap(  
        FarmersCountVO::getCode, // 键映射函数  
        FarmersCountVO::getName  // 值映射函数  
    ));  

//或者
Map<String, String> farmerMap = farmerList.stream()  
    .collect(Collectors.toMap(  
        FarmersCountVO::getCode, // 键映射函数  
        Function.identity()  // 值映射函数(这里表示流中的元素本身)
    ));
  
// 这里假设每个区域代码在列表中只出现一次

2. 处理键冲突

如果流中的元素可能会产生键冲突(即多个元素映射到同一个键),你需要提供一个合并函数:

Map<String, String> farmerMap = farmerList.stream()  
    .collect(Collectors.toMap(  
        FarmersCountVO::getCode, // 键映射函数  
        FarmersCountVO::getName, // 值映射函数  
        (existing, replacement) -> existing + ", " + replacement // 合并函数  
    ));  
  
// 这里合并函数将同一个键的多个值连接成一个字符串

3. 使用 Map.MergeFunction

在 Java 8 中,合并函数通常是一个 BinaryOperator<U>,但在 Java 9 及更高版本中,你也可以使用 Map.MergeFunction<K,V,V> 来明确指定合并逻辑:

Map<String, String> farmerMap = farmerList.stream()  
    .collect(Collectors.toMap(  
        FarmersCountVO::getCode,  
        FarmersCountVO::getName,  
        Map.mergeFunction(String::concat) // 假设你想使用String的concat方法合并值,但注意concat只接受一个参数  
        // 注意:上面的用法实际上是不正确的,因为concat需要两个参数。  
        // 正确的方式是像之前那样使用lambda表达式。但这里只是展示Map.MergeFunction的用法。  
        // 正确的合并字符串的lambda应该是 (existing, replacement) -> existing + replacement  
    ));  
  
// 正确的使用方式还是使用lambda表达式来处理合并逻辑

注意:Map.MergeFunction 的直接应用可能不像上面的示例那样直接,因为 Map.mergeFunction 并不是 Collectors.toMap 方法的一个直接参数。我上面提到的 Map.MergeFunction 主要是为了说明合并函数的概念,并指出在 Java API 中存在这样的函数式接口。然而,在 Collectors.toMap 的上下文中,你通常会直接传递一个 lambda 表达式或方法引用来作为合并函数。

4. 结论

Collectors.toMap 是处理流元素并将其收集到 Map 中的强大工具。通过指定键和值的映射函数以及(可选的)合并函数,你可以灵活地控制如何将流中的元素转换为 Map。

5. 举个工作中的栗子

有个时候可以避免对两个list操作采用双重for循环

//获取一些regionCode区域代码集合
List<String> regionCodeList = farmerAndFeedingStatisticsList.stream()
                    .map(FarmersCountVO::getCode)
                    .collect(Collectors.toList());
//根据regionCode获取对应的经纬度坐标集合
List<RegionPosition> regionPositionList = 
              regionPositionMapper.selectByCodeList(regionCodeList);
//将经纬度坐标集合转为map,键为regionCode,值为对应的经纬度对象
Map<String, RegionPosition> regionPositionMap = 
              MappingUtils.toMap(regionPositionList, RegionPosition::getCode);
for (FarmersCountVO farmersCountVO : farmerAndFeedingStatisticsList) {
     //根据map中键获取对应的值,避免了双重for循环
     RegionPosition regionPosition = regionPositionMap.get(farmersCountVO.getCode());
     farmersCountVO.setCoordinate(regionPosition == null ? new ArrayList<>() :
     Arrays.asList(regionPosition.getLongitude(), regionPosition.getLatitude()));
}

上述代码中的工具类,本质还是Collectors.toMap

/**
     * 将统计列表映射成 E -> T
     * 属性名 -》 属性数据
     *
     * @param source
     * @param function
     * @return
     */
    public static <E, T> Map<E, T> toMap(List<T> source, Function<T, E> function) {
        if (source == null || source.isEmpty()) {
            return new HashMap<>();
        }
        return source.stream().collect(Collectors.toMap(function, Function.identity()));
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值