0

0

Java Stream API:优雅实现条件式BigDecimal求和

花韻仙語

花韻仙語

发布时间:2025-11-08 20:07:15

|

874人浏览过

|

来源于php中文网

原创

java stream api:优雅实现条件式bigdecimal求和

本教程详细阐述如何利用Java Stream API,将传统的基于`for-each`循环和`switch`语句的条件式`BigDecimal`求和逻辑,转换为更简洁、函数式的实现。通过结合`map()`操作进行条件转换(巧妙运用`BigDecimal.negate()`处理减法),并最终使用`reduce()`方法进行累加,展示了Stream API在处理复杂数据聚合场景中的强大能力和代码优雅性,从而提升代码的可读性和维护性。

在数据处理和财务计算中,根据特定条件对数值进行聚合求和是一个非常常见的需求。例如,从一系列交易记录中计算账户余额,通常需要根据交易类型(如收入、支出)对金额进行加减操作。传统上,这通常通过迭代集合并结合switch语句来实现。然而,Java 8引入的Stream API提供了一种更现代、函数式且通常更简洁的解决方案。

传统条件求和方法

在Java中,一个典型的场景是从数据库获取一组交易摘要,然后根据每笔交易的类型来累加或扣除金额以计算总和。假设我们有一个TransactionSumView接口,它包含交易类型(type)和金额(amount):

public interface TransactionSumView {
    String getType();
    BigDecimal getAmount();
}

使用传统的for-each循环和switch语句实现条件求和的代码可能如下所示:

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

import java.math.BigDecimal;
import java.util.List;

// 假设 transactionsRepository.findAllSumByAcc1IdGroupByType(id) 返回 List
List listSum = transactionsRepository.findAllSumByAcc1IdGroupByType(id);

BigDecimal sum = BigDecimal.ZERO; // 初始化总和为零

// 遍历列表,根据类型进行加减操作
for (TransactionSumView transaction : listSum) {
    switch (transaction.getType()) {
        case "E": // 支出
        case "T": // 转账
            sum = sum.subtract(transaction.getAmount());
            break;
        case "I": // 收入
            sum = sum.add(transaction.getAmount());
            break;
        // 可以添加default处理未知类型
    }
}

System.out.println("传统方法计算的总和: " + sum);

这种方法直观易懂,但在处理更复杂的数据流操作时,可能会显得冗长,并且不够“声明式”。

LogoMaker
LogoMaker

免费在线制作Logo,在几分钟内完成标志设计

下载

使用Java Stream API实现条件求和

Stream API提供了一种更流畅的方式来处理集合数据。对于上述条件求和问题,我们可以结合map()和reduce()操作来实现相同的功能。

核心思路

  1. 映射 (Map):首先,将原始的TransactionSumView对象流转换为一个BigDecimal值的流。在这个映射过程中,根据交易类型,我们将金额转换为其最终参与求和的值(即,如果是支出或转账,则将其金额取负数;如果是收入,则保持正数)。
  2. 规约 (Reduce):然后,对这个BigDecimal值的流执行规约操作,将所有值累加起来,得到最终的总和。

详细实现

我们利用Stream.map()方法对每个TransactionSumView对象进行转换。在转换逻辑中,使用三元运算符结合String.equals()来判断交易类型。关键之处在于,对于需要扣除的金额(例如类型"E"和"T"),我们使用BigDecimal.negate()方法将其转换为负数。这样,后续的求和操作就可以统一进行加法。

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors; // 引入Collectors以便在需要时使用

// 假设 listSum 已经从 repository 获取
List listSum = transactionsRepository.findAllSumByAcc1IdGroupByType(id);

// 使用Stream API计算总和
BigDecimal sumWithStream = listSum.stream()
    // 映射操作:根据交易类型转换金额
    .map(transaction -> "I".equals(transaction.getType()) ? // 如果是收入类型
        transaction.getAmount() : // 保持金额为正
        transaction.getAmount().negate() // 否则(支出或转账),将金额取负
    )
    // 规约操作:将所有转换后的金额累加
    .reduce(BigDecimal.ZERO, BigDecimal::add); // 初始值为BigDecimal.ZERO,使用BigDecimal::add进行累加

System.out.println("Stream API计算的总和: " + sumWithStream);

代码解析

  • listSum.stream(): 将List转换为一个Stream
  • .map(transaction -> ...): 这是一个中间操作,它接收一个Function作为参数,将流中的每个元素转换成另一种类型。在这里,我们将每个TransactionSumView对象转换为一个BigDecimal。
    • "I".equals(transaction.getType()): 判断当前交易的类型是否为"I"(收入)。
    • transaction.getAmount(): 如果是收入,则直接使用其金额(正数)。
    • transaction.getAmount().negate(): 如果不是收入(即支出或转账),则调用BigDecimal.negate()方法,将金额转换为负数。例如,如果原始金额是100.00,negate()会返回-100.00。
  • .reduce(BigDecimal.ZERO, BigDecimal::add): 这是一个终端操作,它将流中的所有元素规约成一个单一的结果。
    • BigDecimal.ZERO: 这是规约操作的初始值(identity)。当流为空时,reduce方法将返回此值。
    • BigDecimal::add: 这是一个BinaryOperator,用于将当前累加结果与流中的下一个元素进行合并。由于我们在map阶段已经将支出转换为负数,这里只需要统一进行加法操作即可。

优点与注意事项

优点:

  • 简洁性与可读性: Stream API 版本通常比传统的for-each循环更简洁,尤其是在处理多重转换和聚合时。它以声明式的方式表达“做什么”而不是“如何做”。
  • 函数式编程: 遵循函数式编程范式,强调不可变性(原始TransactionSumView对象未被修改),使代码更易于理解和测试。
  • 并行化潜力: 对于大型数据集,Stream API 可以轻松地通过parallelStream()转换为并行流,从而利用多核处理器提高性能(尽管对于BigDecimal操作,并行化的开销可能需要仔细评估)。

注意事项:

  • 可读性权衡: 对于不熟悉Stream API的开发者来说,过于复杂的map逻辑可能会降低初期可读性。在实际应用中,应根据团队的熟悉程度和逻辑的复杂性进行权衡。
  • 性能考量: 对于小型集合,Stream API的性能开销可能略高于传统循环。但对于大型集合,其优化和并行化潜力可能带来显著优势。
  • BigDecimal的精确性: 在进行财务计算时,始终使用BigDecimal以避免浮点数精度问题至关重要。Stream API与BigDecimal的结合使用完美地保留了这一特性。

总结

通过本教程,我们学习了如何利用Java Stream API,特别是map()和reduce()操作,结合BigDecimal.negate()方法,优雅地实现基于条件逻辑的BigDecimal求和。这种方法不仅提供了更简洁、更具声明性的代码,也符合现代Java编程的函数式风格。掌握这种模式将有助于开发者编写出更高效、更易维护的数据处理代码。

相关专题

更多
java
java

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

652

2023.06.15

java流程控制语句有哪些
java流程控制语句有哪些

java流程控制语句:1、if语句;2、if-else语句;3、switch语句;4、while循环;5、do-while循环;6、for循环;7、foreach循环;8、break语句;9、continue语句;10、return语句。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

455

2024.02.23

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

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

722

2023.07.05

java自学难吗
java自学难吗

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

725

2023.07.31

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

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

394

2023.08.01

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

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

398

2023.08.02

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

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

441

2023.08.02

java有什么用
java有什么用

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

427

2023.08.02

虚拟号码教程汇总
虚拟号码教程汇总

本专题整合了虚拟号码接收验证码相关教程,阅读下面的文章了解更多详细操作。

25

2025.12.25

热门下载

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

精品课程

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

共23课时 | 2万人学习

C# 教程
C# 教程

共94课时 | 5.3万人学习

Java 教程
Java 教程

共578课时 | 38万人学习

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

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