Skip to content
章节导航

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  // 合并函数(通常不会用到)
            ));
    }