0

0

使用Java 8 Stream API重构集合操作:条件更新与元素过滤

花韻仙語

花韻仙語

发布时间:2025-11-22 20:56:01

|

655人浏览过

|

来源于php中文网

原创

使用java 8 stream api重构集合操作:条件更新与元素过滤

本教程探讨如何利用Java 8的Stream API和Optional特性,将传统命令式循环中的条件数据更新和集合元素过滤逻辑进行现代化重构。我们将详细展示如何通过`forEach`结合`Optional.ifPresent()`处理条件赋值,以及如何高效使用`removeIf`进行集合元素的删除,从而提升代码的简洁性与可读性。

原始代码分析

在Java 8之前,处理集合中的元素通常依赖于传统的for或foreach循环。以下是一个典型的示例方法,它负责根据外部数据源更新集合中对象的属性,并移除特定条件的元素:

private Item getItemManufacturerPriceCodes(Item item) {
    List itemPriceCodes = item.getItemPriceCodes();

    // 遍历并根据条件更新ItemPriceCode的属性
    for (ItemPriceCode ipc : itemPriceCodes) {
        Optional mpc = manufacturerPriceCodesRepository
            .findByManufacturerIDAndPriceCodeAndRecordDeleted(item.getManufacturerID(), ipc.getPriceCode(), NOT_DELETED);

        if (mpc.isPresent()) {
            ipc.setManufacturerPriceCode(mpc.get().getName());
        }
    }

    // 移除满足特定条件的ItemPriceCode
    item.getItemPriceCodes()
        .removeIf(ipc -> DELETED.equals(ipc.getRecordDeleted()));

    return item;
}

这段代码的功能包括:

  1. 遍历item对象中的itemPriceCodes列表。
  2. 对于列表中的每一个ItemPriceCode,根据其属性和item的manufacturerID从manufacturerPriceCodesRepository中查找对应的ManufacturerPriceCodes。
  3. 如果找到了匹配的ManufacturerPriceCodes,则将其name属性设置到当前的ItemPriceCode对象上。
  4. 最后,从itemPriceCodes列表中移除所有标记为DELETED的元素。

这种命令式风格的代码虽然功能明确,但在处理复杂逻辑时可能显得冗长,且Java 8引入的Stream API提供了更简洁、声明式的替代方案。

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

Java 8 Stream API重构核心理念

Java 8的Stream API旨在提供一种声明式处理数据集合的方式,它允许我们以更简洁、更具表达力的方式执行过滤、映射、排序等操作。

在重构上述代码时,我们需要理解几个关键概念:

  • forEach用于副作用操作: Stream API鼓励无副作用的操作,但当需要对集合中的现有对象进行修改(即产生副作用)时,forEach是一个常用的终端操作。它遍历流中的每个元素并执行提供的操作,但不会生成新的流或集合。
  • Optional处理可能缺失的值: Optional是Java 8引入的容器对象,用于表示一个值可能存在或不存在。它有助于避免NullPointerException,并提供了如ifPresent()等方法来优雅地处理值存在的情况。
  • removeIf进行集合过滤: Collection接口在Java 8中新增了removeIf方法,它接受一个Predicate函数式接口作为参数,并移除所有满足该条件的元素。这是一种非常高效且简洁的集合过滤方式。
  • map与forEach的区别 原始问题中提到了map。理解map和forEach的区别至关重要。map操作用于将流中的每个元素转换成另一种类型或值,并生成一个包含这些新元素的新流。它通常是无副作用的,用于数据转换。而forEach则用于对流中的每个元素执行一个操作,通常包含副作用(如修改对象状态)。在本场景中,由于需要修改ItemPriceCode对象的内部状态,forEach是更直接且推荐的选择,因为我们不是要将ItemPriceCode转换为其他类型,而是要更新它。

重构步骤详解

我们将分两步重构原始代码中的两个主要逻辑块。

1. 重构条件数据更新逻辑

原始代码中的for循环用于遍历itemPriceCodes,并根据条件查询数据库后更新ItemPriceCode的属性。我们可以使用Stream.forEach()结合Optional.ifPresent()来替代这个循环。

旧代码片段:

Vondy
Vondy

下一代AI应用平台,汇集了一流的工具/应用程序

下载
for (ItemPriceCode ipc : itemPriceCodes) {
    Optional mpc = manufacturerPriceCodesRepository
        .findByManufacturerIDAndPriceCodeAndRecordDeleted(item.getManufacturerID(), ipc.getPriceCode(), NOT_DELETED);

    if (mpc.isPresent()) {
        ipc.setManufacturerPriceCode(mpc.get().getName());
    }
}

Java 8 重构:

item.getItemPriceCodes().forEach(ipc -> {
    // 执行数据库查询,返回Optional
    manufacturerPriceCodesRepository
        .findByManufacturerIDAndPriceCodeAndRecordDeleted(item.getManufacturerID(), ipc.getPriceCode(), NOT_DELETED)
        // 如果Optional中存在值,则执行setManufacturerPriceCode操作
        .ifPresent(mpc -> ipc.setManufacturerPriceCode(mpc.getName()));
});

在这个重构中:

  • 我们直接对item.getItemPriceCodes()返回的列表调用forEach方法,这会为列表中的每个ItemPriceCode执行Lambda表达式。
  • 在Lambda表达式内部,我们执行数据库查询,它返回一个Optional
  • 我们利用Optional的ifPresent()方法。如果Optional包含一个值(即mpc存在),则执行提供的Lambda表达式,将mpc.getName()设置到ipc上。这种方式比传统的if (mpc.isPresent()) { ... mpc.get() ... }更简洁和安全。

2. 重构集合元素过滤逻辑

原始代码的第二部分是使用removeIf方法移除满足特定条件的元素。值得注意的是,removeIf方法本身就是Java 8引入的,它已经是一种非常现代和高效的集合操作方式。

旧代码片段:

item.getItemPriceCodes()
    .removeIf(ipc -> DELETED.equals(ipc.getRecordDeleted()));

Java 8 重构:

此部分代码无需额外重构,因为它已经完全符合Java 8的风格。

item.getItemPriceCodes()
    .removeIf(ipc -> DELETED.equals(ipc.getRecordDeleted()));

完整的Java 8重构代码

将上述两部分重构整合到一起,最终的方法将变得更加简洁和声明式:

import java.util.List;
import java.util.Optional;

// 假设 Item, ItemPriceCode, ManufacturerPriceCodes, ManufacturerPriceCodesRepository, NOT_DELETED, DELETED 已经定义

public class ItemService {

    private ManufacturerPriceCodesRepository manufacturerPriceCodesRepository; // 注入或实例化

    // 构造函数或setter用于注入repository
    public ItemService(ManufacturerPriceCodesRepository manufacturerPriceCodesRepository) {
        this.manufacturerPriceCodesRepository = manufacturerPriceCodesRepository;
    }

    private Item getItemManufacturerPriceCodes(Item item) {
        // 1. 重构条件数据更新逻辑
        item.getItemPriceCodes().forEach(ipc -> {
            manufacturerPriceCodesRepository
                .findByManufacturerIDAndPriceCodeAndRecordDeleted(item.getManufacturerID(), ipc.getPriceCode(), NOT_DELETED)
                .ifPresent(mpc -> ipc.setManufacturerPriceCode(mpc.getName()));
        });

        // 2. 重构集合元素过滤逻辑 (已是Java 8风格)
        item.getItemPriceCodes()
            .removeIf(ipc -> DELETED.equals(ipc.getRecordDeleted()));

        return item;
    }

    // 假设的实体和Repository接口
    static class Item {
        private String manufacturerID;
        private List itemPriceCodes;

        public Item(String manufacturerID, List itemPriceCodes) {
            this.manufacturerID = manufacturerID;
            this.itemPriceCodes = itemPriceCodes;
        }

        public String getManufacturerID() { return manufacturerID; }
        public List getItemPriceCodes() { return itemPriceCodes; }
    }

    static class ItemPriceCode {
        private String priceCode;
        private String manufacturerPriceCode;
        private String recordDeleted; // DELETED or NOT_DELETED

        public ItemPriceCode(String priceCode, String recordDeleted) {
            this.priceCode = priceCode;
            this.recordDeleted = recordDeleted;
        }

        public String getPriceCode() { return priceCode; }
        public String getManufacturerPriceCode() { return manufacturerPriceCode; }
        public void setManufacturerPriceCode(String manufacturerPriceCode) { this.manufacturerPriceCode = manufacturerPriceCode; }
        public String getRecordDeleted() { return recordDeleted; }
    }

    static class ManufacturerPriceCodes {
        private String name;

        public ManufacturerPriceCodes(String name) { this.name = name; }
        public String getName() { return name; }
    }

    interface ManufacturerPriceCodesRepository {
        Optional findByManufacturerIDAndPriceCodeAndRecordDeleted(String manufacturerID, String priceCode, String recordStatus);
    }

    // 假设的常量
    static final String NOT_DELETED = "N";
    static final String DELETED = "Y";
}

注意事项与最佳实践

  1. 数据库查询的性能考虑: 在forEach循环中执行数据库查询(如findByManufacturerIDAndPriceCodeAndRecordDeleted)可能会导致“N+1”查询问题,即每处理一个ItemPriceCode就进行一次数据库查询。如果itemPriceCodes列表非常大,这会严重影响性能。
    • 优化建议: 考虑在forEach之前批量查询所有可能需要的ManufacturerPriceCodes,例如,收集所有priceCode,然后执行一次批量查询(如findByManufacturerIDAndPriceCodeInAndRecordDeleted),将结果映射到Map中,以便在forEach内部进行快速查找。
  2. Stream的副作用: 虽然forEach允许副作用(修改外部状态),但在Stream管道的其他中间操作(如map, filter)中应尽量避免副作用,以保持Stream的函数式纯净性,提高代码的可预测性和并行处理能力。
  3. 可读性与简洁性: Java 8 Stream API旨在提高代码的简洁性和可读性。然而,过度复杂的Stream链可能会适得其反。始终权衡代码的表达力与理解成本。
  4. Optional的使用: Optional的主要目的是为了明确表示一个值可能缺失,从而避免NullPointerException。通过ifPresent(), orElse(), orElseThrow()等方法,可以更优雅地处理值缺失的场景。

总结

通过本教程,我们学习了如何利用Java 8的Stream API和Optional特性,将传统的命令式for循环和条件逻辑重构为更简洁、声明式的代码。特别是使用forEach结合Optional.ifPresent()处理集合元素的条件更新,以及利用removeIf高效过滤集合,都显著提升了代码的可读性和维护性。在实际应用中,还需注意数据库查询等操作可能带来的性能影响,并采取相应的优化策略。

相关专题

更多
java
java

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

832

2023.06.15

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

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

738

2023.07.05

java自学难吗
java自学难吗

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

734

2023.07.31

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

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

397

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基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

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

430

2023.08.02

java在线网站
java在线网站

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

16925

2023.08.03

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

63

2026.01.14

热门下载

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

精品课程

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

共23课时 | 2.5万人学习

C# 教程
C# 教程

共94课时 | 6.7万人学习

Java 教程
Java 教程

共578课时 | 46.1万人学习

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

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