莆田市网站建设_网站建设公司_页面权重_seo优化
2026/1/16 7:01:26 网站建设 项目流程

Collectors.toMap()是 Java 8 Stream API 中用于将流元素收集到 Map 中的收集器。它有多种重载形式。这里主要以3个参数版做介绍,并给出其他参数版本的用法。

1. 三参数版本Collectors.toMap()

1.1 签名(处理重复键

3个参数版Collectors.toMap()方法可以处理重复键,完整签名如下:

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

泛型参数<T, K, U>的含义:

  • T: 流中元素的类型(Type of stream elements)
  • K: 生成 Map 的键的类型(Key type)
  • U: 生成 Map 的值的类型(Ualue type)

返回值类型:Collector<T, ?, Map<K,U>>

  • 第一个T: 输入元素的类型(与流元素类型一致)
  • 第二个?: 累加器(accumulator)的类型,这里是通配符,表示我们不关心具体的累加器实现
  • 第三个Map<K,U>: 最终收集结果的类型
  • 简单理解:这是一个能将T类型元素收集到Map<K,U>中的收集器。

第1个入参 Function<? super T, ? extends K> keyMapper:

  • Function: 函数式接口,接受一个参数,返回一个结果
    • ? super T: 表示参数类型可以是TT的父类(下界通配符
    • ? extends K: 表示返回类型可以是KK的子类(上界通配符
  • 这个函数的作用:从流中的每个元素T提取或转换出 Map 的键K

第2个入参 Function<? super T, ? extends U> valueMapper:

  • 同理,这个函数的作用:从流中的每个元素T提取或转换出 Map 的值U

第3个入参:BinaryOperator<U> mergeFunction:

  • BinaryOperator<U>: 接受两个相同类型U的参数,返回相同类型U结果的函数式接口
  • 作用:当出现重复键时,如何合并两个值

1.2 使用举例

以学生列表转为 Map举例。

// 学生类 @Data class Student { private String id; private String name; private int age; }

使用3个参数版Collectors.toMap()方法举例:

// 无重复key 使用示例 List<Student> students = Arrays.asList( new Student("001", "Alice", 20), new Student("002", "Bob", 22), new Student("003", "Charlie", 21) ); // 以 ID 为键,Student 对象为值 Map<String, Student> studentMap = students.stream() .collect(Collectors.toMap( Student::getId, // keyMapper: T=Student -> K=String Function.identity(), // valueMapper: T=Student -> U=Student (existing, replacement) -> existing // mergeFunction: 保留已存在的 ));
//---------补充说明--------------------------- // Function.identity() 是 Java 8 函数式编程中的一个重要静态方法,可以理解为 "恒等函数" 或 "原样返回函数"。这个函数接收什么就返回什么,不做任何转换。 // 这三种写法是等价的: Function<String, String> func1 = Function.identity(); Function<String, String> func2 = s -> s; Function<String, String> func3 = (String s) -> s;

当有重复key时,第3个入参“合并策略”就发挥作用了:

// 有重复key 使用示例: 第3个入参“合并策略”就发挥作用了 List<Student> studentsWithDuplicate = Arrays.asList( new Student("001", "Alice", 20), new Student("002", "Bob", 22), new Student("001", "Alice_new", 25) // 重复的 ID ); // 保留新值(后出现的) Map<String, Student> mapKeepNew = studentsWithDuplicate.stream() .collect(Collectors.toMap( Student::getId, Function.identity(), (oldValue, newValue) -> newValue // 保留新值 )); // 保留旧值(先出现的) Map<String, Student> mapKeepOld = studentsWithDuplicate.stream() .collect(Collectors.toMap( Student::getId, s -> s, (oldValue, newValue) -> oldValue // 保留旧值 ));
// 自定义合并逻辑1(比如合并年龄信息) Map<String, Integer> ageSumMap = studentsWithDuplicate.stream() .collect(Collectors.toMap( Student::getId, Student::getAge, // value 是 Integer 类型 Integer::sum // 合并函数:求和 <=> (a1,a2)-> a1+a2 )); // 结果: {"001": 45, "002": 22} // 自定义合并逻辑2 (合并name信息) Map<String, Student> mergeUsers = studentsWithDuplicate.stream() .collect(Collectors.toMap( Student::getId, Function.identity(), (student1, student2) -> { // 比如合并用户信息 return new Student(student1.getId(), student1.getName() + "_" + student1.getName()); } ));

2. 其他版本的Collectors.toMap()

2.1 两参数版本

2.1.1 签名(最基础)

public static <T, K, U> Collector<T, ?, Map<K, U>> toMap( Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper )

说明

  • keyMapper: 将流中的每个元素 T 转换为 Map 的键 K
  • valueMapper: 将流中的每个元素 T 转换为 Map 的值 U
  • 限制:不允许重复的键,否则抛出IllegalStateException

2.1.2 使用举例

无重复key 使用示例:

// 基础对象转Map List<Student> students = Arrays.asList( new Student("001", "Alice", 20), new Student("002", "Bob", 22), new Student("003", "Charlie", 21) ); // 姓名作为key,年龄作为value Map<String, Integer> nameToAge = students.stream() .collect(Collectors.toMap(Student::getName, Person::getAge)); // 结果: {Alice=20, Bob=22, Charlie=21} // 对象本身作为value Map<String, Student> nameToPerson = students.stream() .collect(Collectors.toMap(Student::getName, Function.identity())); // 结果: {Alice=Student{id='001', name='Alice', age=20}, ...}

有重复key 时会抛异常:

List<Student> studentsWithDuplicate = Arrays.asList( new Student("001", "Alice", 20), new Student("002", "Bob", 22), new Student("001", "Alice_new", 25) // 重复的 ID ); // 这行代码会抛出异常! Map<Long, Student> userMap2 = studentsWithDuplicate.stream() .collect(Collectors.toMap(Student::getId, Function.identity())); // 抛出: IllegalStateException: Duplicate key Student{id=001, name='Alice', age=20}

2.2 四参数版本

2.2.1 签名(指定Map实现)

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 )

说明

  • 前三个参数同上
  • mapSupplier: 提供具体的 Map 实现类的构造函数引用

2.2.2 使用举例

List<Person> people = Arrays.asList( new Person("Charlie", 35), new Person("Alice", 25), new Person("Bob", 30) ); // LinkedHashMap - 保持插入顺序 Map<String, Integer> linkedMap = people.stream() .collect(Collectors.toMap( Person::getName, Person::getAge, (v1, v2) -> v1, LinkedHashMap::new )); // 结果: {Charlie=35, Alice=25, Bob=30} (保持原始顺序)
// TreeMap - 按键自然排序 Map<String, Integer> treeMap = people.stream() .collect(Collectors.toMap( Person::getName, Person::getAge, (v1, v2) -> v1, TreeMap::new )); // 结果: {Alice=25, Bob=30, Charlie=35} (按键字母排序)
// ConcurrentHashMap - 线程安全 Map<String, Integer> concurrentMap = people.stream() .collect(Collectors.toMap( Person::getName, Person::getAge, (v1, v2) -> v1, ConcurrentHashMap::new ));

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询