Java Stream 中 List 转 Map 的方法教程

一、基础用法:Collectors.toMap()

1. 基本语法
Map<K, V> map = list.stream().collect(Collectors.toMap(
    元素 -> key,    // key映射函数
    元素 -> value   // value映射函数
));
2. 简单示例:List<Person> → Map<Long, String>
// 准备数据
List<Person> people = Arrays.asList(
    new Person(1L, "张三", 25),
    new Person(2L, "李四", 30),
    new Person(3L, "王五", 28)
);

// 转Map:id为key,name为value
Map<Long, String> idNameMap = people.stream()
    .collect(Collectors.toMap(
        Person::getId,     // key: Person的id
        Person::getName    // value: Person的name
    ));
// 结果:{1=张三, 2=李四, 3=王五}
3. 元素本身作为 value
// id为key,Person对象本身为value
Map<Long, Person> idPersonMap = people.stream()
    .collect(Collectors.toMap(
        Person::getId,
        person -> person  // 或 Function.identity()
    ));

二、处理重复 key:提供合并策略

当 List 中有重复 key 时,必须指定冲突解决方案,否则会抛 IllegalStateException

List<Person> people = Arrays.asList(
    new Person(1L, "张三", 25),
    new Person(1L, "张三丰", 30),  // key重复
    new Person(2L, "李四", 28)
);

// 保留后者
Map<Long, String> map1 = people.stream()
    .collect(Collectors.toMap(
        Person::getId,
        Person::getName,
        (oldValue, newValue) -> newValue  // 冲突时取新值
    ));

// 保留前者
Map<Long, String> map2 = people.stream()
    .collect(Collectors.toMap(
        Person::getId,
        Person::getName,
        (oldValue, newValue) -> oldValue  // 冲突时取旧值
    ));

// 拼接
Map<Long, String> map3 = people.stream()
    .collect(Collectors.toMap(
        Person::getId,
        Person::getName,
        (v1, v2) -> v1 + "," + v2  // 拼接:张三,张三丰
    ));


三、指定 Map 类型

默认返回 HashMap,可指定返回 LinkedHashMap 或 TreeMap

// 返回 LinkedHashMap(保持插入顺序)
Map<Long, String> linkedMap = people.stream()
    .collect(Collectors.toMap(
        Person::getId,
        Person::getName,
        (v1, v2) -> v2,           // 合并策略
        LinkedHashMap::new         // 指定Map类型
    ));

// 返回 TreeMap(按key排序)
Map<Long, String> treeMap = people.stream()
    .collect(Collectors.toMap(
        Person::getId,
        Person::getName,
        (v1, v2) -> v2,
        TreeMap::new
    ));

四、Collectors.groupingBy():一对多分组

当需要将 List 转为 Map<K, List<V>> 时使用。

List<Person> people = Arrays.asList(
    new Person(1L, "张三", 25),
    new Person(2L, "李四", 25),
    new Person(3L, "王五", 30),
    new Person(4L, "赵六", 30)
);

// 1. 按年龄分组:Map<Integer, List<Person>>
Map<Integer, List<Person>> ageGroup = people.stream()
    .collect(Collectors.groupingBy(Person::getAge));
// 结果:{
//   25=[Person(1,张三,25), Person(2,李四,25)],
//   30=[Person(3,王五,30), Person(4,赵六,30)]
// }

// 2. 分组后提取某个字段:Map<Integer, List<String>>
Map<Integer, List<String>> ageNames = people.stream()
    .collect(Collectors.groupingBy(
        Person::getAge,
        Collectors.mapping(Person::getName, Collectors.toList())
    ));
// 结果:{25=[张三, 李四], 30=[王五, 赵六]}

// 3. 分组后计数:Map<Integer, Long>
Map<Integer, Long> ageCount = people.stream()
    .collect(Collectors.groupingBy(
        Person::getAge,
        Collectors.counting()
    ));
// 结果:{25=2, 30=2}

// 4. 指定返回 LinkedHashMap(保持key的顺序)
Map<Integer, List<Person>> orderedGroup = people.stream()
    .collect(Collectors.groupingBy(
        Person::getAge,
        LinkedHashMap::new,
        Collectors.toList()
    ));

五、常见异常及解决

异常原因解决
IllegalStateException: Duplicate keykey 重复且未指定合并策略添加第三个参数 (v1,v2)->v2
NullPointerExceptionvalue 为 null改用 collect(HashMap::new, (m,v)->m.put(k,v), ...) 或过滤 null
类型推断失败Lambda 表达式模糊显式声明参数类型或方法引用
// 处理 value 为 null 的情况
Map<Long, String> map = people.stream()
    .collect(HashMap::new, 
             (m, v) -> m.put(v.getId(), v.getName()), 
             HashMap::putAll);

六、方法速查表

需求方法示例
List → Map(1:1)toMap(key, value)toMap(Person::getId, Person::getName)
List → Map(有重复key)toMap(key, value, merge)toMap(Person::getId, Person::getName, (v1,v2)->v2)
List → Map(指定类型)toMap(key, value, merge, mapType)toMap(..., LinkedHashMap::new)
List → 分组Map(1:N)groupingBy(classifier)groupingBy(Person::getAge)
分组+聚合groupingBy(classifier, downstream)groupingBy(Person::getAge, counting())

掌握这些,Java Stream 的 List 转 Map 操作就基本没问题了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值