toMap
将流元素收集到 Map 中。它有多个重载版本,提供不同的功能。
java
// 1. 最基本的版本 - 指定键和值的提取器
toMap(Function keyMapper, Function valueMapper)
// 2. 处理键冲突的版本
toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)
// 3. 指定具体 Map 实现的版本
toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction, Supplier mapSupplier)基础用法 - 简单转换
java
import java.util.*;
import java.util.stream.*;
public class ToMapBasic {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 35)
);
// 转换为 Map<姓名, 年龄>
Map<String, Integer> nameToAge = people.stream()
.collect(Collectors.toMap(
Person::getName, // 键提取器
Person::getAge // 值提取器
));
System.out.println(nameToAge);
// {Alice=25, Bob=30, Charlie=35}
// 转换为 Map<姓名, Person对象>
Map<String, Person> nameToPerson = people.stream()
.collect(Collectors.toMap(
Person::getName,
person -> person // 值就是对象本身
));
}
}处理键冲突(重复键)
java
public class ToMapWithMerge {
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("Alice", "Math", 85),
new Student("Bob", "Science", 90),
new Student("Alice", "Science", 88), // 相同的名字
new Student("Charlie", "Math", 92)
);
// ❌ 这样会抛出异常:Duplicate key Alice
// Map<String, Integer> map = students.stream()
// .collect(Collectors.toMap(
// Student::getName,
// Student::getScore
// ));
// ✅ 使用合并函数处理冲突
Map<String, Integer> map1 = students.stream()
.collect(Collectors.toMap(
Student::getName,
Student::getScore,
(oldValue, newValue) -> newValue // 保留新值
));
System.out.println(map1); // {Alice=88, Bob=90, Charlie=92}
// 求相同键的和
Map<String, Integer> map2 = students.stream()
.collect(Collectors.toMap(
Student::getName,
Student::getScore,
Integer::sum // 合并函数:求和
));
System.out.println(map2); // {Alice=173, Bob=90, Charlie=92}
// 取最大值
Map<String, Integer> map3 = students.stream()
.collect(Collectors.toMap(
Student::getName,
Student::getScore,
Math::max // 合并函数:取最大值
));
System.out.println(map3); // {Alice=88, Bob=90, Charlie=92}
}
}指定具体的 Map 实现
java
public class ToMapWithSupplier {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 35)
);
// 使用 TreeMap(按键排序)
TreeMap<String, Integer> sortedMap = people.stream()
.collect(Collectors.toMap(
Person::getName,
Person::getAge,
(oldVal, newVal) -> newVal,
TreeMap::new // Map 工厂
));
System.out.println(sortedMap); // 按字母顺序排序
// 使用 LinkedHashMap(保持插入顺序)
LinkedHashMap<String, Integer> orderedMap = people.stream()
.collect(Collectors.toMap(
Person::getName,
Person::getAge,
(oldVal, newVal) -> newVal,
LinkedHashMap::new
));
// 使用 ConcurrentHashMap(线程安全)
ConcurrentHashMap<String, Integer> concurrentMap = people.stream()
.collect(Collectors.toMap(
Person::getName,
Person::getAge,
(oldVal, newVal) -> newVal,
ConcurrentHashMap::new
));
}
}实际应用示例
示例 1:分组统计
java
public static void main(String[] args) {
List<Order> orders = Arrays.asList(
new Order("Alice", "Laptop", 1200),
new Order("Bob", "Phone", 800),
new Order("Alice", "Mouse", 50),
new Order("Charlie", "Laptop", 1200),
new Order("Bob", "Headphones", 150)
);
// 按客户分组,计算总消费金额
Map<String, Double> customerTotalSpent = orders.stream()
.collect(Collectors.toMap(
Order::getCustomerName,
Order::getAmount,
Double::sum
));
System.out.println(customerTotalSpent);
// {Alice=1250.0, Bob=950.0, Charlie=1200.0}
// 按产品分组,统计销售数量
Map<String, Long> productSalesCount = orders.stream()
.collect(Collectors.toMap(
Order::getProduct,
order -> 1L,
Long::sum
));
System.out.println(productSalesCount);
// {Laptop=2, Phone=1, Mouse=1, Headphones=1}
}示例 2:对象转换
java
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User(1, "Alice", "alice@example.com"),
new User(2, "Bob", "bob@example.com"),
new User(3, "Charlie", "charlie@example.com")
);
// ID -> User 对象
Map<Integer, User> idToUser = users.stream()
.collect(Collectors.toMap(
User::getId,
Function.identity() // user -> user
));
// ID -> 用户名
Map<Integer, String> idToName = users.stream()
.collect(Collectors.toMap(
User::getId,
User::getName
));
// 邮箱 -> User 对象
Map<String, User> emailToUser = users.stream()
.collect(Collectors.toMap(
User::getEmail,
Function.identity()
));
}示例 3:复杂对象收集
java
static class Department {
private String name;
private List<Employee> employees;
// getters, setters
}
static class Employee {
private String name;
private String role;
private double salary;
// getters, setters
}
public static void main(String[] args) {
List<Department> departments = getDepartments();
// 收集所有员工的姓名和部门对应关系
Map<String, String> employeeToDept = departments.stream()
.flatMap(dept -> dept.getEmployees().stream()
.map(emp -> new AbstractMap.SimpleEntry<>(emp.getName(), dept.getName())))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(dept1, dept2) -> dept1 + "/" + dept2 // 处理重复员工名
));
// 部门->最高薪水的员工
Map<String, Employee> deptToHighestPaid = departments.stream()
.collect(Collectors.toMap(
Department::getName,
dept -> dept.getEmployees().stream()
.max(Comparator.comparing(Employee::getSalary))
.orElse(null),
(e1, e2) -> e1 // 合并函数(通常不会用到)
));
}
朔风