Java中Stream API处理Map初始化的操作方法

 更新时间:2025年10月10日 14:42:26   作者:BirdMan98  
Stream API提供了多种方式来实现Map的构建、存在则更新、不存在则添加的操作,本文通过实例代码介绍Java中Stream API处理Map初始化的操作方法,感兴趣的朋友一起看看吧

当然可以! Stream API 提供了多种方式来实现 Map 的构建、存在则更新、不存在则添加的操作。以下是几种常用的方法:

1. 使用Collectors.toMap()处理重复键

import java.util.*;
import java.util.stream.Collectors;
public class StreamMapOperations {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("Alice", 25),
            new Person("Bob", 30),
            new Person("Alice", 28), // 重复的key
            new Person("Charlie", 35)
        );
        // 方法1: 使用toMap的合并函数来处理重复键
        Map<String, Integer> personMap = people.stream()
            .collect(Collectors.toMap(
                Person::getName,      // key映射器
                Person::getAge,       // value映射器
                (existing, newValue) -> newValue // 合并函数:新值覆盖旧值
            ));
        System.out.println("覆盖策略: " + personMap);
        // 输出: {Alice=28, Bob=30, Charlie=35}
    }
}
class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() { return name; }
    public int getAge() { return age; }
}

2. 不同的合并策略

// 合并函数的不同实现策略
Map<String, Integer> map1 = people.stream()
    .collect(Collectors.toMap(
        Person::getName,
        Person::getAge,
        (oldValue, newValue) -> oldValue // 保留旧值
    ));
Map<String, Integer> map2 = people.stream()
    .collect(Collectors.toMap(
        Person::getName,
        Person::getAge,
        (oldValue, newValue) -> oldValue + newValue // 求和
    ));
Map<String, List<Integer>> map3 = people.stream()
    .collect(Collectors.toMap(
        Person::getName,
        person -> new ArrayList<>(Arrays.asList(person.getAge())),
        (oldList, newList) -> {
            oldList.addAll(newList);
            return oldList;
        }
    ));
System.out.println("保留旧值: " + map1); // {Alice=25, Bob=30, Charlie=35}
System.out.println("求和: " + map2);     // {Alice=53, Bob=30, Charlie=35}
System.out.println("收集所有值: " + map3); // {Alice=[25, 28], Bob=[30], Charlie=[35]}

3. 复杂的对象操作

class Product {
    private String category;
    private String name;
    private double price;
    private int quantity;
    public Product(String category, String name, double price, int quantity) {
        this.category = category;
        this.name = name;
        this.price = price;
        this.quantity = quantity;
    }
    // getters
    public String getCategory() { return category; }
    public String getName() { return name; }
    public double getPrice() { return price; }
    public int getQuantity() { return quantity; }
}
public class ComplexMapOperations {
    public static void main(String[] args) {
        List<Product> products = Arrays.asList(
            new Product("Electronics", "Laptop", 1000, 2),
            new Product("Electronics", "Phone", 500, 5),
            new Product("Books", "Novel", 20, 10),
            new Product("Electronics", "Laptop", 900, 3) // 重复商品,价格不同
        );
        // 按商品名称分组,计算总价值(价格*数量)
        Map<String, Double> productValueMap = products.stream()
            .collect(Collectors.toMap(
                Product::getName,
                product -> product.getPrice() * product.getQuantity(),
                Double::sum // 存在则累加
            ));
        System.out.println("商品总价值: " + productValueMap);
        // 输出: {Laptop=4700.0, Phone=2500.0, Novel=200.0}
    }
}

4. 分组收集器的高级用法

// 按类别分组,并收集每个类别的商品列表
Map<String, List<Product>> productsByCategory = products.stream()
    .collect(Collectors.groupingBy(Product::getCategory));
// 按类别分组,并计算每个类别的总价值
Map<String, Double> categoryTotalValue = products.stream()
    .collect(Collectors.groupingBy(
        Product::getCategory,
        Collectors.summingDouble(p -> p.getPrice() * p.getQuantity())
    ));
// 按类别分组,并获取每个类别最贵的商品
Map<String, Optional<Product>> mostExpensiveByCategory = products.stream()
    .collect(Collectors.groupingBy(
        Product::getCategory,
        Collectors.maxBy(Comparator.comparingDouble(Product::getPrice))
    ));
System.out.println("按类别分组: " + productsByCategory.keySet());
System.out.println("类别总价值: " + categoryTotalValue);

5. 自定义Map操作(更复杂的逻辑)

// 如果存在则更新,不存在则添加的复杂逻辑
Map<String, ProductStats> productStatsMap = products.stream()
    .collect(Collectors.toMap(
        Product::getName,
        product -> new ProductStats(1, product.getPrice() * product.getQuantity(), product.getPrice()),
        (existingStats, newStats) -> {
            // 存在则更新:数量累加,总价值累加,价格取平均值
            int totalCount = existingStats.getCount() + newStats.getCount();
            double totalValue = existingStats.getTotalValue() + newStats.getTotalValue();
            double avgPrice = totalValue / (existingStats.getCount() + newStats.getCount());
            return new ProductStats(totalCount, totalValue, avgPrice);
        }
    ));
class ProductStats {
    private int count;
    private double totalValue;
    private double averagePrice;
    public ProductStats(int count, double totalValue, double averagePrice) {
        this.count = count;
        this.totalValue = totalValue;
        this.averagePrice = averagePrice;
    }
    // getters and toString
}

6. 使用collect的三参数版本

// 更底层的实现方式
Map<String, Integer> manualMap = products.stream()
    .collect(
        HashMap::new, // 供应商:创建新的Map
        (map, product) -> {
            // 累加器:处理每个元素
            String key = product.getName();
            int value = product.getQuantity();
            map.merge(key, value, Integer::sum); // 存在则求和,不存在则添加
        },
        HashMap::putAll // 组合器:用于并行流
    );

7. 处理并发Map

// 线程安全的ConcurrentMap
ConcurrentMap<String, Integer> concurrentMap = products.stream()
    .collect(Collectors.toConcurrentMap(
        Product::getName,
        Product::getQuantity,
        Integer::sum
    ));

8. 完整的实战示例

public class CompleteMapExample {
    public static void main(String[] args) {
        List<Transaction> transactions = Arrays.asList(
            new Transaction("ACC001", "DEPOSIT", 1000),
            new Transaction("ACC001", "WITHDRAW", 200),
            new Transaction("ACC002", "DEPOSIT", 500),
            new Transaction("ACC001", "DEPOSIT", 300),
            new Transaction("ACC003", "DEPOSIT", 1500)
        );
        // 按账户分组,计算余额(存款为正,取款为负)
        Map<String, Double> accountBalances = transactions.stream()
            .collect(Collectors.toMap(
                Transaction::getAccountNumber,
                transaction -> {
                    double amount = transaction.getAmount();
                    if ("WITHDRAW".equals(transaction.getType())) {
                        amount = -amount;
                    }
                    return amount;
                },
                Double::sum // 存在则累加余额
            ));
        System.out.println("账户余额:");
        accountBalances.forEach((account, balance) -> 
            System.out.println(account + ": " + balance)
        );
    }
}
class Transaction {
    private String accountNumber;
    private String type;
    private double amount;
    public Transaction(String accountNumber, String type, double amount) {
        this.accountNumber = accountNumber;
        this.type = type;
        this.amount = amount;
    }
    // getters
}

关键总结

  1. Collectors.toMap() 是主要工具,第三个参数是合并函数
  2. 合并函数 (oldValue, newValue) -> {...} 决定了存在时的更新策略
  3. 多种策略:覆盖、累加、取最大值、收集到列表等
  4. 线程安全:使用 toConcurrentMap() 处理并发场景
  5. 分组收集groupingBy() 用于更复杂的分组操作

Stream API 提供了非常强大的 Map 操作能力,完全可以实现"存在则更新,不存在则添加"的需求!

到此这篇关于Java中Stream API处理Map初始化的文章就介绍到这了,更多相关Java Stream API处理Map初始化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mybatis自定义SQL的关系映射、分页、排序功能的实现

    Mybatis自定义SQL的关系映射、分页、排序功能的实现

    这篇文章主要介绍了Mybatis自定义SQL的关系映射、分页、排序功能的实现,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • spring cloud实现Eureka注册中心的HA的方法

    spring cloud实现Eureka注册中心的HA的方法

    本篇文章主要介绍了spring cloud实现Eureka注册中心的HA的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • spring boot微服务自定义starter原理详解

    spring boot微服务自定义starter原理详解

    这篇文章主要介绍了spring boot微服务自定义starter原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Java实现顺时针输出螺旋二维数组的方法示例

    Java实现顺时针输出螺旋二维数组的方法示例

    这篇文章主要介绍了利用Java如何实现顺时针输出螺旋二维数组的方法示例,文中给出了详细的示例代码和注释,相信对大家具有一定的参考价值,有需要的朋友们下面来一起看看吧。
    2017-02-02
  • BeanPostProcessor在显示调用初始化方法前修改bean详解

    BeanPostProcessor在显示调用初始化方法前修改bean详解

    这篇文章主要介绍了BeanPostProcessor在显示调用初始化方法前修改bean详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • 详解Java设计模式之外观模式

    详解Java设计模式之外观模式

    在Java开发中,设计模式是一种十分常见的编程思想,它可以帮助我们解决很多实际开发中的问题,本篇文章将介绍一种常见的设计模式——外观模式,并结合实际的开发场景进行讲解,需要的朋友可以参考下
    2023-06-06
  • springboot配置嵌入式servlet容器的方法

    springboot配置嵌入式servlet容器的方法

    这篇文章主要介绍了springboot配置嵌入式servlet容器的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • 基于Java的guava开源库工具类

    基于Java的guava开源库工具类

    guava是谷歌基于java封装好的开源库,这篇文章主要通过介绍几个好用的guava工具类,感兴趣的朋友可以参考下面文章内容
    2021-09-09
  • Spring Cloud LoadBalancer 负载均衡详解

    Spring Cloud LoadBalancer 负载均衡详解

    本文介绍了如何在Spring Cloud中使用SpringCloudLoadBalancer实现客户端负载均衡,并详细讲解了轮询策略和随机策略的配置方法,此外,还提供了部署到云服务器并在多个实例之间进行负载均衡的步骤,感兴趣的朋友一起看看吧
    2025-02-02
  • Spring MVC中处理ajax请求的跨域问题与注意事项详解

    Spring MVC中处理ajax请求的跨域问题与注意事项详解

    跨域问题是我们大家在开发中会经常遇到的一个问题,所以下面这篇文章主要给大家介绍了关于Spring MVC中处理ajax请求的跨域问题与注意事项的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2017-11-11

最新评论