Java8 Stream API中实现集合list转map的多种方式

 更新时间:2025年12月10日 09:01:21   作者:codingPower  
这篇文章介绍了如何使用Java8的StreamAPI对QuotaDto对象列表进行操作,包括字段提取、映射、组装成Map、枚举类处理、元素拼接、聚合函数以及去重,文章的示例代码讲解详细,感兴趣的小伙伴可以了解下

自定义一个对象:

public class QuotaDto{
	private Long id;
	private String quotaId;
	private String quotaName;
	private String reportDate;
	private String email;
}

List<QuotaDto>  quotaDtolists = new ArrayList<>();

1. 提取对象字段集合

List<String> quotaNames = quotaDtolists.stream()
        .map(QuotaDto::getQuotaName)
        .filter(Objects::nonNull) // 过滤null值
        .collect(Collectors.toList());

优化点

使用 filter(Objects::nonNull) 避免 null 元素进入列表。

2. List转Map(唯一键)

// 方式1:对象为Value(处理重复键)
Map<String, QuotaDto> quotaMap1 = quotaDtolists.stream()
        .collect(Collectors.toMap(
            QuotaDto::getQuotaId, 
            Function.identity(),
            (v1, v2) -> v2 // 键冲突时保留新值
        ));

// 方式2:提取字段为Value
Map<String, String> quotaMap2 = quotaDtolists.stream()
        .collect(Collectors.toMap(
            QuotaDto::getQuotaId,
            QuotaDto::getQuotaName,
            (oldVal, newVal) -> newVal
        ));

关键点

必须提供合并函数 ((v1, v2) -> ...),否则重复键会抛出 IllegalStateException

3. 枚举类转Map(修正版)

public enum QuotaEnum {
    TYPE_A("A"), TYPE_B("B");

    private final String value;

    QuotaEnum(String value) { this.value = value; }
    public String getValue() { return value; } // 正确方法名

    // 枚举转Map
    private static final Map<String, QuotaEnum> VALUE_MAP = Arrays.stream(values())
            .collect(Collectors.toMap(QuotaEnum::getValue, Function.identity()));
}

修正

  • 方法名 getvaluegetValue(遵循驼峰命名)。
  • 使用 Arrays.stream() 替代 Stream.of()(更直观)。

4. List转Map(类型安全版)

List<Map<String, String>> lists = new ArrayList<>(); // 统一泛型类型
//(v1,v2)->v2 冲突解决函数,当两个不同的map对象具有相同的“userid”键值。保留第二个遇到的值V2
Map<String, String> collect = lists.stream()
        .collect(Collectors.toMap(
            map -> map.getOrDefault("userid", ""),
            map -> map.getOrDefault("orgid", ""),
            (v1, v2) -> v2
        ));

//以某个字段为key
Map<String,List<QuotaDto>> quotaMap= quotaDtolists.stream().collect(Collectors.groupingBy(QuotaDto::getQuotaName));

//list<map> 转 map
Map<String,List<Map<String,String>>> quotaMap= maps.stream().collect(Collectors.groupingBy(map->map.get("userId")));

修正

  • 统一列表中的 Map 泛型为 <String, String>,避免类型不匹配。
  • 使用 getOrDefault 防止 null 值导致的 NullPointerException

5. 元素拼接(防Null版)

String emailAddress = quotaDtolists.stream()
        .map(quota -> Optional.ofNullable(quota.getEmail())
                .map(email -> email.toUpperCase() + "@qq.com")
                .orElse("")) // 处理null或空邮件
        .filter(str -> !str.isEmpty())
        .collect(Collectors.joining(";"));
        
//简单版
String emailAddress=quotaDtolists.stream().map(Quota-Quota.getEmail().toUpperCase()+"@qq.com").collect(Collectors.joining(";"));

优化

使用 Optional 安全处理 null,并过滤空字符串。

6. 聚合操作(安全版)

List<Integer> list = Arrays.asList(1, 2, 3);
// 最大值(避免NoSuchElementException)
Integer maxValue = list.stream()
        .max(Integer::compare)
        .orElse(0); // 默认值

Integer maxValue2 = list.stream().collect(Collectors.collectingAndThen(Collectors.maxBy((a, b) -> a - b), Optional::get));

// 最小值
Integer minValue = list.stream()
        .min(Integer::compare)
        .orElse(0);
    
Integer minValue2 = list.stream().collect(Collectors.collectingAndThen(Collectors.minBy((a, b) -> a - b), Optional::get));

// 求和(直接使用sum()更高效)
int sumValue = list.stream().mapToInt(Integer::intValue).sum();

Integer sumValue2 = list.stream().collect(Collectors.summingInt(item -> item));

// 平均值
Double avg = list.stream()
        .mapToInt(Integer::intValue)
        .average()
        .orElse(0.0);

Double avg2 = list.stream().collect(Collectors.averagingDouble(x -> x));
    
// 求汇总数
long count= quotaDtolists.stream().filter(Quota-> Quota.getId()>1).collect(Collectors.counting());

优化

  • 直接使用 max()min()sum() 等终端操作,代码更简洁。
  • 避免使用复杂的 collectingAndThen,除非需要额外处理。

7. 多字段去重(可靠版)

ArrayList<QuotaDto> uniqueList = quotaDtolists.stream()
        .collect(Collectors.collectingAndThen(
            Collectors.toCollection(() -> new TreeSet<>(
                Comparator.comparing(QuotaDto::getId)
                          .thenComparing(QuotaDto::getQuotaName)
            )), 
            ArrayList::new
        ));


//方法二
ArrayList<QuotaDto> collect = quotaDtolists.stream().collect(Collectors.collectingAndThen(
            Collectors.toCollection(() -> new TreeSet<>(
                    Comparator.comparing(q -> q.getId()+";"+q.getQuotaName()))), ArrayList::new));

修正

使用 thenComparing 组合多个字段的比较,避免字符串拼接可能导致的键冲突。

最佳实践总结

  • 空值处理:始终考虑字段可能为 null 的情况,使用 filterOptional 防御。
  • 类型安全:统一集合的泛型类型,避免 ClassCastException
  • 键冲突处理:在 toMap 中始终提供合并函数,明确冲突解决策略。
  • 避免魔法字符串:如 map.get("userid") 可替换为常量,提高可维护性。
  • 优先内置方法:如 sum()average()Collectors.summingInt 更简洁。
  • 使用组合比较器:多字段去重时,避免拼接字符串,采用 thenComparing

通过遵循这些原则,可以大幅提升代码的健壮性和可读性。

到此这篇关于Java8 Stream API中实现集合list转map的多种方式的文章就介绍到这了,更多相关Java Stream list转map内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解JAVA中的OPTIONAL

    详解JAVA中的OPTIONAL

    从Java 8引入的一个很有趣的特性是Optional类。Optional类主要解决的问题是臭名昭著的空指针异常(NullPointerException)
    2021-06-06
  • java经典问题:连个字符串互为回环变位

    java经典问题:连个字符串互为回环变位

    连个字符串互为回环变位经常出现在java程序员面试中,这个是考验程序员的解题思路和方法的最经典的一题,小编为大家详细分析一下,一起来学习吧。
    2017-11-11
  • Spring WebFlux实现参数校验的示例代码

    Spring WebFlux实现参数校验的示例代码

    请求参数校验,在实际的应用中很常见,网上的文章大部分提供的使用注解的方式做参数校验。本文主要介绍 Spring Webflux Function Endpoint 使用 Spring Validation 来校验请求的参数。感兴趣的可以了解一下
    2021-08-08
  • Spring boot按日切分spring boot的nohup.out日志文件的方法

    Spring boot按日切分spring boot的nohup.out日志文件的方法

    过大的日志文件维护起来存在诸多问题,所以最好是能够按日或按大小切分日志文件,下面小编给大家带来了Spring boot按日切分spring boot的nohup.out日志文件的方法,一起看看吧
    2018-08-08
  • Java中如何检查数组是否包含某整数

    Java中如何检查数组是否包含某整数

    这篇文章主要介绍了在 Java 中检查数组是否包含某整数,在本文中,我们使用了几个内置的方法,如anyMatch()、contains()、binarySearch()等,我们将在给定的数组中找到一个值,结合示例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • idea git设置Local Changes窗口过程(代码/文件变更显示)

    idea git设置Local Changes窗口过程(代码/文件变更显示)

    本文介绍了在IDEA中,当代码有变更但未显示LocalChanges窗口时,可以通过设置取消勾选“Usenon-modalcommitinterface”选项来解决该问题
    2026-04-04
  • RocketMQ中的消息发送与消费详解

    RocketMQ中的消息发送与消费详解

    这篇文章主要介绍了RocketMQ中的消息发送与消费详解,RocketMQ是一款高性能、高可靠性的分布式消息中间件,消费者是RocketMQ中的重要组成部分,消费者负责从消息队列中获取消息并进行处理,需要的朋友可以参考下
    2023-10-10
  • Java中的字节流InputStream和OutputStream详解

    Java中的字节流InputStream和OutputStream详解

    这篇文章主要介绍了Java中的字节流InputStream和OutputStream详解,继承自InputStream的流都是用于向程序中输入数据,且数据的单位为字节8bit,我们看到的具体的某一些管道,凡是以InputStream结尾的管道,都是以字节的形式向我们的程序输入数据,需要的朋友可以参考下
    2023-10-10
  • Java的stream流多个字段排序的实现

    Java的stream流多个字段排序的实现

    本文主要介绍了Java的stream流多个字段排序的实现,主要是两种方法,第一种是固定多个字段排序和第二种动态字段进行排序,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • java基础--JDK SPI概述

    java基础--JDK SPI概述

    SPI是一种服务发现机制,本文就SPI做了详细概述,具有很好的参考价值,希望对小伙伴们有所帮助,感兴趣的朋友一起来参考参考吧
    2021-08-08

最新评论