Java中使用Stream API优化for循环

业务逻辑:计算总额

原来使用for的逻辑代码

// 计算总额
double total = 0.0;
for (RkDetail rkDetail: rkDetailList) {
    if (rkDetail.getTotal() != null) {
        total += rkDetail.getTotal();
    }
}

使用Java 8 Stream API实现,使代码更简洁且易读 

// 计算总额
double total = rkDetailList.stream()
    .filter(r -> r.getTotal() != null)
    .mapToDouble(RkDetail::getTotal)
    .sum();

让我们一步步拆解这段代码的含义,用生活中快递分拣的场景帮助你理解:

double total = rkDetailList.stream()      // 【开启传送带】
    .filter(r -> r.getTotal() != null)    // 【安检仪-过滤空包裹】
    .mapToDouble(RkDetail::getTotal)      // 【拆包取物】
    .sum();                               // 【自动累加】

1. 开启传送带 rkDetailList.stream()

想象你有一个装满快递包裹的货架(rkDetailList),现在要启动一条传送带处理这些包裹。
stream() 就像启动传送带,让包裹(列表中的每个 RkDetail 对象)依次进入处理流程。

📦📦📦📦 包裹们排着队进入传送带...


2. 安检仪过滤 filter(r -> r.getTotal() != null)

传送带上的第一个设备是安检仪,它会检查每个包裹:
r -> r.getTotal() != null 表示 "只允许装有金额的包裹通过"
(这里的 r 代表每个快递包裹,getTotal() 查看包裹内的金额单)

✅ 有金额单的包裹通过
❌ 空包裹(金额单为null)被丢弃

📦✅ -> 金额100元
📦❌ -> 金额单丢失
📦✅ -> 金额50元
📦✅ -> 金额200元


3. 拆包取物 mapToDouble(RkDetail::getTotal)

通过安检的包裹来到拆包工位,这里的工作人员会:
RkDetail::getTotal 表示 "拆开包裹,只取出里面的金额单"
mapToDouble 将金额单上的数字转换为计算机能直接计算的数值(double类型)

输入:📦✅ -> 输出:100.0
输入:📦✅ -> 输出:50.0
输入:📦✅ -> 输出:200.0


4. 自动累加 sum()

最后来到自动累加器,它会将所有金额单上的数值相加:
sum() 自动完成 100.0 + 50.0 + 200.0 = 350.0

💰 最终总额:350.0


完整流程示意图

原始包裹队列 → [传送带] → [安检过滤] → [拆包取数] → [自动求和]
   (List)      (stream())   (filter)     (mapToDouble)   (sum)

重点记忆口诀

  1. 流式处理三步走:取流 → 过滤 → 转换

  2. 箭头符号看数据-> 左边是输入,右边是处理逻辑

  3. 双冒号是快捷方式类名::方法名 等价于 x -> x.方法名()

实际案例演示

假设原始数据:

RkDetail 包裹1 = new RkDetail(100.0);
RkDetail 包裹2 = new RkDetail(null);    // 空包裹
RkDetail 包裹3 = new RkDetail(50.0);
List<RkDetail> rkDetailList = Arrays.asList(包裹1, 包裹2, 包裹3);

代码执行过程:

  1. 包裹2 在 filter 阶段被过滤

  2. 包裹1 和 包裹3 的金额被提取

  3. 计算 100.0 + 50.0 = 150.0

最终 total 的值为 150.0

通过这种生活化的类比,是不是更容易理解Stream流的工作原理了呢?在实际开发中,这种处理方式比传统for循环更直观,尤其适合处理复杂的数据流水线操作。

 

优化点说明:

  1. Stream API 替代显式循环

    • 通过流式操作 stream() + filter() + mapToDouble() + sum() 链式调用,消除手动循环和中间变量,代码更简洁

    • 逻辑表达更声明式(描述做什么,而非如何做)

  2. 空值过滤更直观

    • filter(r -> r.getTotal() != null) 直接体现空值过滤逻辑,一目了然

  3. 避免中间状态变量

    • 原始代码需要维护 total 变量和循环体,流式操作直接通过无状态计算得到结果

扩展优化建议(视场景选用):

  1. 并行流加速

    java

    复制

    下载

    // 仅当列表极大且线程安全时使用
    double total = rkDetailList.parallelStream()
        .filter(r -> r.getTotal() != null)
        .mapToDouble(RkDetail::getTotal)
        .sum();
  2. 空集合防御

    java

    复制

    下载

    // 如果 rkDetailList 可能为 null(根据业务场景决定是否添加)
    List<RkDetail> safeList = Optional.ofNullable(rkDetailList).orElse(Collections.emptyList());
    double total = safeList.stream()... // 后续操作同上
  3. 方法引用(若允许空值)

    java

    复制

    下载

    // 如果 RkDetail::getTotal 不可能返回 null(注意与当前场景冲突)
    double total = rkDetailList.stream()
        .mapToDouble(RkDetail::getTotal)
        .sum();

最终选择建议:
若运行环境是Java 8+且列表规模可控,推荐使用基础优化版本,兼顾简洁性与可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值