0

0

使用Java Stream API高效聚合数据:按类别计算平均价格

DDD

DDD

发布时间:2025-09-22 12:06:49

|

1076人浏览过

|

来源于php中文网

原创

使用Java Stream API高效聚合数据:按类别计算平均价格

本文将深入探讨如何利用Java Stream API高效地处理对象列表,实现按特定属性(如类别)进行分组,并计算相应数值属性(如价格)的平均值。通过Collectors.groupingBy和Collectors.averagingDouble的组合应用,能够以简洁、声明式的方式将复杂的数据聚合逻辑转化为一行代码,显著提升代码的可读性和维护性。

场景描述

在实际开发中,我们经常需要处理包含多种类型或类别的数据集合。例如,给定一个building(建筑)对象的列表,每个building对象都包含price(价格)、neighborhood(社区)和category(类别)等属性。我们的目标是计算每个category下所有building的平均price,并将结果存储在一个map中,其中键是category,值是该类别的平均价格。

为了更好地理解,我们首先定义相关的类结构:

import java.util.Objects;

// 假设Category是一个枚举类型或简单类
class Category {
    private String name;

    public Category(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Category{" + "name='" + name + '\'' + '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Category category = (Category) o;
        return Objects.equals(name, category.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

class Building {
    private int price;
    private String neighborhood;
    private Category category;

    public Building(int price, String neighborhood, Category category) {
        this.price = price;
        this.neighborhood = neighborhood;
        this.category = category;
    }

    public int getPrice() {
        return price;
    }

    public String getNeighborhood() {
        return neighborhood;
    }

    public Category getCategory() {
        return category;
    }

    @Override
    public String toString() {
        return "Building{" +
               "price=" + price +
               ", neighborhood='" + neighborhood + '\'' +
               ", category=" + category +
               '}';
    }
}

传统迭代方法的挑战

如果没有Java Stream API,我们可能需要通过多步迭代来完成这个任务:

  1. 创建一个Map>来存储每个类别的所有价格。
  2. 遍历Building列表,将每个Building的价格根据其Category添加到对应的列表中。
  3. 再次遍历这个Map,对每个Category的价格列表计算平均值,并将结果存入最终的Map

这种方法代码量较大,逻辑分散,且容易出错。

使用Java Stream API的高效解决方案

Java 8引入的Stream API提供了一种声明式处理数据集合的强大方式。通过结合Collectors.groupingBy和Collectors.averagingDouble,我们可以用一行代码实现上述复杂的数据聚合逻辑。

Replit Agent
Replit Agent

Replit最新推出的AI编程工具,可以帮助用户从零开始自动构建应用程序。

下载

立即学习Java免费学习笔记(深入)”;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.HashMap;
import java.util.ArrayList;

public class BuildingPriceCalculator {

    /**
     * 计算每个类别的平均建筑价格。
     *
     * @param buildings 建筑对象列表。
     * @return 一个Map,键是Category,值是该类别的平均价格。
     */
    public static Map averagePricePerCategory(List buildings) {
        // 如果输入列表为空,直接返回一个空Map
        if (buildings == null || buildings.isEmpty()) {
            return new HashMap<>();
        }

        return buildings.stream() // 将List转换为Stream
                        .collect(Collectors.groupingBy( // 使用groupingBy进行分组
                                Building::getCategory, // 根据Building的Category属性进行分组
                                Collectors.averagingDouble(Building::getPrice) // 对每个分组内的Building,计算其price的平均值
                        ));
    }

    public static void main(String[] args) {
        // 示例数据
        Category residential = new Category("Residential");
        Category commercial = new Category("Commercial");
        Category industrial = new Category("Industrial");

        List buildings = new ArrayList<>();
        buildings.add(new Building(100000, "Downtown", residential));
        buildings.add(new Building(150000, "Suburb", residential));
        buildings.add(new Building(200000, "City Center", commercial));
        buildings.add(new Building(50000, "Outskirts", industrial));
        buildings.add(new Building(120000, "Downtown", residential));
        buildings.add(new Building(250000, "Financial District", commercial));

        Map averagePrices = averagePricePerCategory(buildings);

        System.out.println("各类别平均价格:");
        averagePrices.forEach((category, avgPrice) ->
                System.out.println(category.getName() + ": " + String.format("%.2f", avgPrice))
        );

        // 测试空列表情况
        List emptyBuildings = new ArrayList<>();
        Map emptyAveragePrices = averagePricePerCategory(emptyBuildings);
        System.out.println("\n空列表的平均价格结果: " + emptyAveragePrices); // 预期输出 {}
    }
}

代码解析

  1. buildings.stream(): 首先,我们将输入的List转换为一个Stream。Stream API的所有操作都基于这个流。
  2. .collect(...): collect是一个终端操作,它会消费流中的元素,并将它们聚合为一个结果(这里是一个Map)。它接收一个Collector作为参数。
  3. Collectors.groupingBy(classifier, downstreamCollector): 这是核心的聚合器。
    • classifier (Building::getCategory): 这是一个函数,用于从流中的每个元素(Building对象)中提取用于分组的键。在这里,它会根据每个Building的Category属性进行分组。
    • downstreamCollector (Collectors.averagingDouble(Building::getPrice)): 这是一个嵌套的收集器,用于处理每个分组内的元素。对于每个Category分组,averagingDouble会收集该分组内所有Building对象的price属性,并计算它们的平均值。
      • Building::getPrice: 这是一个函数,用于从Building对象中提取需要计算平均值的double类型数值(这里int会被自动提升为double)。

最终,collect方法会返回一个Map,其中键是Category对象,值是该类别建筑的平均价格。

注意事项与总结

  • 处理空列表: 在averagePricePerCategory方法中,我们添加了一个if (buildings == null || buildings.isEmpty())的检查。虽然Stream API在处理空流时通常会返回一个空集合或默认值(例如,averagingDouble在空分组上会返回0.0),但为了明确性及避免不必要的流操作,预先检查是一个良好的实践。
  • 性能: 对于大规模数据集,Stream API在内部可以利用并行处理(通过parallelStream()),从而在多核处理器上提供更好的性能。然而,对于小规模数据集,并行流的开销可能会抵消其优势。
  • 代码可读性: 相比于传统的循环和条件判断,Stream API的代码更具声明性,它描述了“做什么”而不是“如何做”,使得代码意图更清晰,更易于理解和维护。
  • 类型安全: Stream API的操作都是类型安全的,编译器会在编译时捕获大部分类型错误。
  • 可扩展性: 如果未来需要计算其他聚合指标(如总和、最大值、最小值、计数等),或者需要进行更复杂的组合聚合,Stream API提供了丰富的Collectors选项来满足这些需求。

通过本教程,我们了解了如何利用Java Stream API中的groupingBy和averagingDouble收集器,以一种简洁、高效且声明式的方式,从对象列表中聚合数据并计算按类别分组的平均值。掌握Stream API是现代Java开发中不可或缺的技能,它能显著提升代码质量和开发效率。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

835

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

741

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

736

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

399

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16926

2023.08.03

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

43

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.6万人学习

C# 教程
C# 教程

共94课时 | 7万人学习

Java 教程
Java 教程

共578课时 | 47.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号