【Java 8 新特性】Java 8 Stream filter()方法实战:从基础筛选到复杂业务逻辑

Python学习笔记-PyQt6状态栏 QMainWindow有自带的状态栏,可以通过statusBar()方法获取自身的状态栏,或者通过实例化QStatusBar类,然后使用QMainWindow.setStatusBar()方法将状态栏添加到主窗体。可通过状态栏的addPermanentWidget()方法添加多个控件用于显示信息。 阅读详情

1. 初识Stream filter()方法

第一次接触Java 8的Stream API时,我被filter()方法的简洁优雅深深吸引。记得当时正在处理一个用户列表筛选的需求,传统写法需要写一堆for循环和if判断,而用filter()只需要一行代码就搞定了。这种声明式的编程方式,让代码的可读性提升了不止一个档次。

filter()是Stream API中的一个中间操作,它的作用就像筛子一样,可以根据我们设定的条件过滤出想要的元素。方法签名非常简单: Stream<T> filter(Predicate<? super T> predicate) ,接收一个Predicate函数式接口作为参数,返回一个新的Stream。

举个例子,假设我们有一个用户列表,要筛选出年龄大于18岁的用户。用传统写法可能是这样的:

List<User> adultUsers = new ArrayList<>();
for(User user : userList) {
    if(user.getAge() > 18) {
        adultUsers.add(user);
    }
}

而用Stream filter()可以写成:

List<User> adultUsers = userList.stream()
    .filter(user -> user.getAge() > 18)
    .collect(Collectors.toList());

是不是简洁多了?这种链式调用的写法,就像在组装一条数据处理流水线,每个操作都是一个工序,数据像水流一样经过各个处理环节。

2. filter()基础用法实战

2.1 简单条件过滤

filter()最基本的用法就是根据单一条件过滤集合。比如我们有一个商品列表,要筛选出价格大于100元的商品:

List<Product> expensiveProducts = products.stream()
    .filter(p -> p.getPrice() > 100)
    .collect(Collectors.toList());

这里 p -> p.getPrice() > 100 就是一个Predicate,它定义了过滤条件。在实际项目中,我经常用这种方式快速过滤数据,比写for循环要高效得多。

2.2 多条件组合过滤

有时候我们需要组合多个条件进行过滤,这时可以用逻辑运算符连接多个Predicate。比如要筛选出价格在100到500元之间,且库存大于0的商品:

List<Product> availableMidPriceProducts = products.stream()
    .filter(p -> p.getPrice() > 100 && p.getPrice() < 500 && p.getStock() > 0)
    .collect(Collectors.toList());

也可以把条件拆分开来,这样可读性更好:

Predicate<Product> priceRange = p -> p.getPrice() > 100 && p.getPrice() < 500;
Predicate<Product> inStock = p -> p.getStock() > 0;

List<Product> result = products.stream()
    .filter(priceRange.and(inStock))
    .collect(Collectors.toList());

2.3 处理null值

在实际项目中,我们经常会遇到集合中包含null值的情况。如果不处理,可能会抛出NullPointerException。我吃过这个亏,所以现在都会先过滤掉null值:

List<String> notNullList = list.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.toList());

或者更严格一点,同时检查字符串不为空:

List<String> validStrings = list.stream()
    .filter(s -> s != null && !s.isEmpty())
    .collect(Collectors.toList());

3. filter()与其他Stream操作结合

3.1 与findFirst()/findAny()配合

findFirst()和findAny()都是终端操作,用于从流中获取元素。结合filter()可以很方便地查找符合条件的第一个元素。比如我们要找第一个年龄大于30的用户:

Optional<User> firstAdult = users.stream()
    .filter(u -> u.getAge() > 30)
    .findFirst();

findAny()在并行流中效率更高,因为它不保证返回的是第一个匹配元素。我曾经在一个大数据量处理的场景中,用findAny()替代findFirst(),性能提升了近30%。

3.2 与map()配合使用

map()用于转换流中的元素,经常和filter()一起使用。比如我们要获取所有管理员用户的姓名列表:

List<String> adminNames = users.stream()
    .filter(u -> "admin".equals(u.getRole()))
    .map(User::getName)
    .collect(Collectors.toList());

这种组合在实际开发中非常常见,先过滤再转换,代码一气呵成。

3.3 与reduce()配合统计

reduce()可以用来做归约操作,结合filter()可以实现条件统计。比如计算所有VIP用户的消费总额:

double totalVipSpending = orders.stream()
    .filter(o -> o.getUser().isVip())
    .map(Order::getAmount)
    .reduce(0.0, Double::sum);

4. 复杂业务场景实战

4.1 电商订单筛选

在电商系统中,订单筛选是非常常见的需求。比如我们要筛选出最近一个月内,金额大于500元且未发货的订单:

LocalDate oneMonthAgo = LocalDate.now().minusMonths(1);

List<Order> targetOrders = orders.stream()
    .filter(o -> o.getCreateDate().isAfter(oneMonthAgo))
    .filter(o -> o.getAmount() > 500)
    .filter(o -> !o.isShipped())
    .collect(Collectors.toList());

我曾经优化过一个老项目的订单查询接口,用Stream API替换了原来的多重for循环,代码量减少了60%,性能还提升了15%。

4.2 用户画像过滤

用户画像分析时,经常需要根据多个标签筛选用户。比如要找年龄在25-35岁之间,居住在北上广深,且最近有登录的女性用户:

Set<String> tier1Cities = Set.of("北京", "上海", "广州", "深圳");

List<User> targetUsers = users.stream()
    .filter(u -> u.getAge() >= 25 && u.getAge() <= 35)
    .filter(u -> tier1Cities.contains(u.getCity()))
    .filter(u -> u.getLastLoginDate().isAfter(LocalDate.now().minusDays(30)))
    .filter(u -> u.getGender() == Gender.FEMALE)
    .collect(Collectors.toList());

4.3 日志分析处理

分析服务器日志时,我们可能需要筛选出特定级别的错误日志,并按时间排序:

List<LogEntry> errorLogs = logs.stream()
    .filter(l -> Level.ERROR.equals(l.getLevel()))
    .filter(l -> l.getTimestamp().isAfter(startTime))
    .sorted(Comparator.comparing(LogEntry::getTimestamp))
    .collect(Collectors.toList());

在处理一个线上问题时,我曾经用类似的代码快速定位到了问题时间段的错误日志,大大缩短了故障排查时间。

5. 性能优化与注意事项

5.1 避免重复操作

Stream的每个终端操作都会触发整个流水线的执行,所以要避免重复调用。我曾经见过这样的代码:

// 不好的写法 - 执行了两次终端操作
long count = list.stream().filter(...).count();
List<Result> result = list.stream().filter(...).collect(Collectors.toList());

应该改为:

List<Result> result = list.stream().filter(...).collect(Collectors.toList());
long count = result.size();

5.2 注意操作顺序

Stream操作顺序会影响性能。一般来说,filter()应该尽量靠前,这样可以减少后续操作的数据量。比如:

// 更好的顺序
List<String> names = users.stream()
    .filter(u -> u.getAge() > 18)  // 先过滤
    .map(User::getName)            // 再转换
    .collect(Collectors.toList());

5.3 并行流的使用

对于大数据集,可以考虑使用并行流:

List<User> adultUsers = users.parallelStream()
    .filter(u -> u.getAge() > 18)
    .collect(Collectors.toList());

但要注意并行流不是万能的,它有一定的开销,对于小数据集可能反而更慢。我在一个包含百万级数据的处理任务中测试过,并行流比顺序流快了近3倍。

5.4 对象引用问题

使用filter()过滤对象集合时要注意,过滤后的集合中的对象仍然是原集合中对象的引用。这意味着如果修改过滤后的对象,原集合中的对象也会被修改。如果需要完全独立的副本,需要手动创建新对象:

List<User> copiedUsers = users.stream()
    .filter(u -> u.getAge() > 18)
    .map(u -> new User(u))  // 使用拷贝构造函数
    .collect(Collectors.toList());

6. 常见问题与解决方案

6.1 如何处理过滤结果为空的情况

使用Stream API时,经常会遇到过滤结果可能为空的情况。Optional可以很好地处理这种情况:

Optional<User> optionalUser = users.stream()
    .filter(u -> u.getId() == targetId)
    .findFirst();

optionalUser.ifPresent(user -> {
    // 处理找到的用户
});

6.2 复杂条件的封装

当过滤条件变得复杂时,可以考虑将Predicate封装成方法或类,提高代码可读性:

public Predicate<User> isEligibleForPromotion() {
    return u -> u.getAge() >= 18 
        && u.getPurchaseCount() >= 5
        && u.getLastPurchaseDate().isAfter(LocalDate.now().minusMonths(3));
}

List<User> eligibleUsers = users.stream()
    .filter(isEligibleForPromotion())
    .collect(Collectors.toList());

6.3 调试Stream操作

调试Stream操作可能不太直观,可以使用peek()方法查看流经的元素:

List<User> result = users.stream()
    .peek(u -> System.out.println("Processing: " + u))
    .filter(u -> u.getAge() > 18)
    .peek(u -> System.out.println("After filter: " + u))
    .collect(Collectors.toList());

在实际项目中,我经常用这个技巧来排查Stream处理过程中的问题。

Stream API在实际项目中的应用:数据筛选与转换 通过本小节的学习,我们掌握了 Stream API 在实际项目中进行数据筛选和转换的操作。我们学会了使用filter方法进行数据筛选,使用map方法进行数据转换,以及如何将这两个操作结合起来进行综合处理。同时,我们还解决了一些实际项目中可能遇到的业务逻辑问题,如处理空值和复杂的筛选条件。掌握了 Stream API 数据筛选和转换的内容后,下一节我们将深入学习 Stream API 在实际项目中的其他操作,如数据排序、分组和聚合等,进一步完善对本章 Stream API 实战应用主题的认知。🔖。 阅读详情

相关推荐

Python filter()函数原理与实战:从真值测试到流式筛选

filter() 是 Python 内置的高阶函数,本质是基于函数式编程思想实现的数据筛选工具,其核心原理是接收一个判定函数和可迭代对象,返回惰性求值的迭代器。它通过封装‘遍历+条件判断+收集’逻辑,显著提升代码可读性与可维护性,技术价值体现在内存友好(懒加载)、管道化组合(如 map/filter/reduce 链式调用)及类型安全(配合 Type Hints)。典型应用场景包括日志流过滤、传感器数据清洗、API 响应空值处理等;尤其在处理大文件或实时数据流时,相比列表推导式更节省内存。本文深入解析其与

chuoshao2508的博客 367

实战wxPython:038 - 状态栏StatusBar

状态栏是一个狭窄的窗口,可以沿着框架的底部放置,以提供少量的状态信息。它可以包含一个或多个字段,其中一个或多个字段的长度可以根据窗口的大小而变化。在wxPython中控件wx.StatusBar提供了状态栏的功能。

seniorwizard的专栏 1480

瑞芯微RK3576开发板实战:6TOPS NPU如何加速你的AIoT项目(附性能测试)

本文以瑞芯微RK3576开发板为核心,深入探讨其6TOPS NPU在AIoT项目中的实战应用。通过详细的性能测试对比,展示了NPU如何将AI模型推理速度提升15倍以上,并大幅降低CPU负载。文章涵盖从环境搭建、模型转换优化到多屏异显与系统级调优的全流程,为开发者提供了将硬件算力转化为实际项目加速效果的完整指南。

oauth7security的博客 820

状态栏 Statusbars@GTK+ 2.0 中文教程连载

状态栏 Statusbars<br />状态栏(Statusbars)是一些简单的构件,一般用来显示文本消息。它将文本消息压入到一个栈里面,当弹出当前消息时,将重新显示前一条文本消息。<br />为 了让应用程序的不同部分使用同一个状态栏显示消息,状态栏构件使用上下文标识符(Context Identifiers)来识别不同“用户”。在栈顶部的消息就是要显示的消息,不管它的上下文是什么。消息在栈里面是以后进先出(last-in- first-out)的方式保存的,而不是按上下文标识符顺序。<br /

uunubt的专栏 995

STM32结合FFT与窗函数优化,实现高精度正弦信号提取

本文详细介绍了如何在STM32嵌入式平台上结合FFT算法与窗函数优化技术,实现高精度正弦信号提取。通过分析频谱泄漏原理,对比汉宁窗、汉明窗等窗函数特性,并提供实际代码示例和幅值补偿方法,有效解决了工业检测中信号精度不足的问题。

v5w6x的博客 221

利用Ghidra与SVD插件实现STM32固件深度逆向分析

本文详细介绍了如何利用Ghidra逆向工程框架结合SVD插件,实现对STM32固件(.bin文件)的深度逆向分析。通过加载描述芯片外设寄存器的SVD文件,Ghidra能将晦涩的硬件地址操作转换为可读的寄存器符号,极大提升了对嵌入式固件中通信协议、安全校验等关键逻辑的分析效率。文章涵盖了从Java环境搭建、工具配置到实战逆向解析的完整流程。

peach的博客 944

如何使用StatusBar控件

我们来看下 定义public class StatusBar : System.Windows.Forms.Control System.Windows.Forms 的成员 摘要: 表示 Windows 状态栏控件。 从工具栏中拽一个StatusBar 控件 .csharpcode, .csharpcode pre { font-size: small; co...

weixin_30871701的博客 589

倾斜摄影与激光点云融合建模:Photoscan+ContextCapture避坑指南

本文详细解析了倾斜摄影与激光点云融合建模的技术流程,重点介绍了使用Agisoft Metashape(原Photoscan)与ContextCapture进行数据融合的实战指南。文章深入探讨了数据预处理、坐标系统一、空三计算策略及在ContextCapture中进行点云配准等关键步骤,旨在帮助从业者规避常见陷阱,高效构建兼具高精度几何与真实纹理的三维实景模型。

weixin_29062613的博客 250

Java List过滤 Stream API filter() 应用

Java List过滤 Stream API filter() 应用

Yeats_Liao的博客 2133

如何让 RTX 5090 开启 PCIE P2P 以加速多卡通信

RTX 5090 基于新的 Blackwell 架构。NVIDIA 出于对某些主板兼容性(如 IOMMU、Resizable BAR 策略)的保守考虑,**屏蔽了 5090 的 BAR1 P2P 功能**。 我们需要通过 Patch 驱动源码,强制开启这一隐藏功能。 开启 P2P 后,PyTorch 的集合通信算子(Multi-GPU 训练的核心)延迟显著降低,**All-Reduce 甚至降低了 60% 以上**。

Hi20240217的博客 1734

37、基于铁电场效应晶体管(FeFET)的片上深度神经网络(DNN)直接反馈对齐训练

本文提出了一种基于铁电场效应晶体管(FeFET)的深度神经网络(DNN)训练加速器架构,结合直接反馈对齐(DFA)算法和FeFET的独特物理特性,以解决当前DNN训练中反向传播(BP)算法带来的高计算开销、复杂数据依赖和高能耗问题。通过设计基于FeFET的MVM引擎、低功耗ADC和随机数生成器(RNG),该架构在速度和功率效率方面相比现有基于ReRAM的加速器分别提升了1.3倍和2.5倍。研究为未来高效能AI训练硬件的发展提供了新的思路和实现路径。

wine的专栏 163

java中jdk8的Stream流的组合进阶用法

​ 我们知道jdk8的一大特色就是推出了Stream流编程,一段冗长的代码,抑或是相对较复杂的业务逻辑,Stream流让一行代码来完成变成了可能! ​ 下面通过一个例子来学习下Stream中的filter、collect等的组合用法,直接上代码吧,具体的请复制到自己的IDE中运行即可,代码书写很简单。 package cn.suvue.discipline.practice.stream; ...

suvue 788

基于Jeecgboot3.9.0的vue3版本前后端分离的flowable流程管理平台

基于Jeecgboot3.9.0的vue3版本前后端分离的flowable流程管理平台

宁波阿成的博客 902

用stream().filter快速验证你的数据处理逻辑

通过。

NightshadeRaven21的博客 669

Qualcomm 常用NV列表

^ NV ITEM ^ 功能^^ |NV10 |mode prefer,找网模式|新平台使用NV80000| ^NV74 NV74=0关闭自动接听电话^ |NV240 |NV240=FALSE|EVDO出现网络的问题,此项必须设定为FALSE| |NV255 |CDMA规避网络列表(SID/NID号)| |NV256 |

sdrgtywretyeruet的专栏 5769

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

从数据筛选到结构重塑:实战解析Stream的filter、map与flatMap核心操作

本文深入解析Java Stream API中的filter、map与flatMap核心操作,通过实战案例展示如何从数据筛选到结构重塑。文章详细介绍了filter的数据筛选技巧、map的数据转换方法以及flatMap处理嵌套结构的强大功能,帮助开发者掌握流式编程思维,提升代码效率与可读性。

weixin_30835649的博客 264

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

从‘查用户’到‘查订单’:手把手教你用Java Stream filter玩转业务数据筛选

本文深入探讨了Java Stream filter在业务数据筛选中的高阶实践,通过对比传统for循环与Stream API的性能差异,展示了如何利用`filter`与`findAny`组合提升代码可读性和维护性。文章结合电商系统实例,详细解析了谓词设计、异常处理、性能优化等实用技巧,帮助开发者高效处理复杂业务逻辑。

weixin_30896511的博客 358

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Java Stream filter多条件组合技巧(资深架构师私藏代码模板)

掌握Java Stream流filter多条件组合技巧,轻松应对复杂数据筛选场景。通过Predicate链式拼接实现动态过滤,提升代码可读性与扩展性,适用于集合处理、业务规则匹配等应用。资深架构师实战经验总结,值得收藏。

LearnFlow的博客 1172

Java8新特性笔记--波哥带你学JAVA--Stream Api

1.集合处理数据的弊端 当我在需要对集合中的元素进行操作的时候,除了必须的添加删除获取外,最典型的操作就是集合遍历 public class Demo01StreamApi { public static void main(String[] args) { // 定义一个集合 List<String> list = Arrays.asList("张三","张三丰","成龙","周星驰"); // 1.获取所有姓张的信息

Fred He的博客 864

Java基础18-Java Stream API:高效处理集合数据

本文介绍了Java 8引入的Stream API,这是一种高效处理集合数据的函数式编程方法。Stream API通过流水线式操作简化集合处理,相比传统迭代方式具有代码简洁、可读性强、易于并行化等优势。文章详细讲解了Stream的核心概念、特点(非存储性、惰性求值等),以及与集合的区别。同时介绍了多种创建Stream的方式,包括从集合、数组、值序列生成,以及创建无限流的方法。通过丰富的代码示例,展示了Stream API在实际开发中的应用场景,为开发者提供了一套更高效、更优雅的数据处理方案。

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

java8 lambda map<list>排序_飞起来!java8 的Stream对集合操作太骚了!

java8 也出来好久了,接口默认方法,lambda 表达式,函数式接口,Date API 等特性还是有必要去了解一下。比如在项目中经常用到集合,遍历集合可以试下 lambda 表达式,经常还要对集合进行过滤和排序,Stream 就派上用场了。用习惯了,不得不说真的很好用。Stream 作为 java8 的新特性,基于 lambda 表达式,是对集合对象功能的增强,它专注于对集合对象进行各种高效、...

weixin_40007175的博客 417

Java8新特性第3章(Stream API)

Stream作为Java8的新特性之一,他与Java IO包中的InputStream和OutputStream完全不是一个概念。Java8中的Stream是对集合功能的一种增强,主要用于对集合对象进行各种非常便利高效的聚合和大批量数据的操作。结合Lambda表达式可以极大的提高开发效率和代码可读性。 假设我们需要把一个集合中的所有形状设置成红色,那么我们可以这样写 for ...

dengwan3818的博客 103

Java Stream浅析

(尊重劳动成果,转载请注明出处:https://yangwenqiang.blog.youkuaiyun.com/article/details/105928523 冷血之心的博客) 前言: 今天终于提起了笔,想对拖延了好几个月的知识点进行一个简单的总结与分析。博主在今年跳槽了,在公司主要做主app业务相关的方向。发现这边大量使用Stream、函数式编程Function来处理一些业务逻辑。在业务逻辑较多的情况下,熟练使用Stream和Function确实是比较方便的一件事。所以,代码中存在着大量的函数式编程代码。 .

冷血之心的博客 695

【Java基础|Stream流:从基础入门到实战进阶,告别繁琐循环!】

本篇文章带你从零开始全面掌握Java Stream流,涵盖核心概念、流创建、中间操作、终端操作、实战案例、常见坑点、性能优化,学完就能在项目中落地使用,彻底告别臃肿的循环代码!

2601_94944967的博客 676

Java 8 Stream API 实战:从循环遍历到函数式编程的效率革命

Java 8 引入的Stream API彻底改变了集合操作的范式,它基于函数式编程思想,通过 “链式调用”“惰性执行” 和 “并行优化”,让复杂的集合操作代码更简洁、更高效、更易维护。Stream API 通过 “抽象集合操作”,将开发者从 “如何遍历” 的细节中解放出来,专注于 “要做什么” 的业务逻辑,其核心价值可概括为 3 点:​。.sorted((u1, u2) -> Integer.compare(u2.getAge(), u1.getAge())) // 降序​。

m0_72256543的博客 909
上一篇: Python序列化实战:pickle模块的深度解析与JSON的抉择指南
下一篇: ElasticSearch——Head插件安装避坑指南与集群监控实战
deepfuture
博客等级 码龄17年 210粉丝 1287原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值