文章目录

    • **一、Stream 流简介**
    • **二、Stream 流核心操作**
      • **1. 创建 Stream**
      • **2. 中间操作(Intermediate Operations)**
        • **filter(Predicate<T>):过滤数据**
          • **1. 简单条件过滤**
          • **2. 多条件组合**
          • **3. 过滤对象集合**
          • **4. 过滤 `null` 值**
        • **2. map(Function<T, R>):转换元素**
          • **一、`map` 的核心特性**
          • **2. 提取对象属性**
          • **3. 复杂转换逻辑**
        • **3. flatMap(Function<T, Stream<R>>):扁平化嵌套结构**
        • **4. distinct():去重**
        • **5. sorted():排序**
        • **6. limit(n) 和 skip(n):分页控制**
    • **三、高级用法**
        • **1. 分组与分区**
        • **2. 并行流处理**
        • **3. 原始类型流**
        • **四、实际应用场景示例**
          • **1. 数据转换与过滤**
          • **2. 统计与汇总**
          • **3. 复杂集合处理**
          • **4. 分组统计**
        • **五、注意事项与最佳实践**
        • **六、与传统循环的对比**

一、Stream 流简介

Java 8 引入的 Stream 提供了一种高效、声明式处理集合数据的方式,支持顺序和并行操作,核心特点包括:

  • 链式调用:通过组合中间操作(如 filter, map)和终端操作(如 collect, forEach)实现复杂逻辑。
  • 延迟执行:只有终端操作触发时才会执行中间操作。
  • 不可重用:每个流只能被消费一次。

二、Stream 流核心操作

1. 创建 Stream

  • 集合创建Collection.stream()parallelStream()

    List<String> list = Arrays.asList("a", "b", "c");
    Stream<String> stream = list.stream();
    
  • 数组创建Arrays.stream(array)

    String[] arr = {"a", "b", "c"};
    Stream<String> stream = Arrays.stream(arr);
    
  • 静态方法Stream.of() 或生成无限流 Stream.iterate(), Stream.generate()

    Stream<Integer> numbers = Stream.of(1, 2, 3);
    Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2); // 0, 2, 4, ...
    

2. 中间操作(Intermediate Operations)

filter(Predicate):过滤数据

作用:根据条件筛选元素,保留满足条件的元素。
示例

List<String> filtered = list.stream().filter(s -> s.startsWith("a"))  // 保留以"a"开头的字符串.collect(Collectors.toList());

最佳实践

1. 简单条件过滤

筛选出符合条件的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);// 筛选所有偶数
List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList()); // [2, 4, 6]
2. 多条件组合

使用逻辑运算符 &&(与)、||(或)组合条件。

List<String> words = Arrays.asList("apple", "banana", "cherry", "date");// 筛选长度大于5 且 以字母a开头的单词
List<String> result = words.stream().filter(s -> s.length() > 5 && s.startsWith("b")).collect(Collectors.toList()); // ["banana"]
3. 过滤对象集合

根据对象属性筛选数据。

class User {String name;int age;// 构造方法、getter/setter 省略
}List<User> users = Arrays.asList(new User("Alice", 25),new User("Bob", 17),new User("Charlie", 30)
);// 筛选年龄 >= 18 的用户
List<User> adults = users.stream().filter(user -> user.getAge() >= 18).collect(Collectors.toList()); // [Alice, Charlie]
4. 过滤 null

使用 Objects::nonNull 过滤掉 null 元素。

List<String> listWithNulls = Arrays.asList("a", null, "b", null, "c");// 过滤掉所有 null 值
List<String> nonNullList = listWithNulls.stream().filter(Objects::nonNull).collect(Collectors.toList()); // ["a", "b", "c"]

2. map(Function<T, R>):转换元素

map 是 Java Stream 中最核心的中间操作之一,用于将流中的元素一对一转换为另一种形式。它的本质是通过一个函数(Function<T, R>)对每个元素进行映射,生成新的元素流。以下是 map 的深入解析,涵盖使用场景、底层机制、最佳实践与常见问题。


一、map 的核心特性
  1. 一对一转换:每个输入元素对应一个输出元素,元素数量不变。
  2. 类型转换:输入类型 T 可转换为任意输出类型 R(如 StringInteger)。
  3. 惰性求值:只有终端操作触发时才会执行映射逻辑。
  4. 无副作用:理想情况下,映射函数不修改外部状态(符合函数式编程原则)。

作用:将元素转换为另一种类型或提取特定属性。

1. 简单类型转换

// 将字符串转换为大写
List<String> upperCaseList = Arrays.asList("apple", "banana", "cherry").stream().map(String::toUpperCase).collect(Collectors.toList()); // ["APPLE", "BANANA", "CHERRY"]
2. 提取对象属性
// 从User对象中提取name属性
List<String> names = users.stream().map(User::getName).collect(Collectors.toList());
3. 复杂转换逻辑
// 将字符串转换为自定义DTO对象
List<DataDTO> dtos = strings.stream().map(s -> {DataDTO dto = new DataDTO();dto.setValue(s.length());dto.setLabel(s.toUpperCase());return dto;}).collect(Collectors.toList());

3. flatMap(Function<T, Stream>):扁平化嵌套结构

作用:将嵌套集合(如 List<List<T>>)展开为单一流。
示例

List<List<String>> nestedList = Arrays.asList(Arrays.asList("a", "b"),Arrays.asList("c", "d")
);
List<String> flatList = nestedList.stream().flatMap(Collection::stream)  // 将每个List<String>转换为Stream<String>.collect(Collectors.toList()); // ["a", "b", "c", "d"]

典型场景

  • 处理数据库查询的多表关联结果。
  • 合并多个API响应的数据列表。

4. distinct():去重

作用:基于 equals()hashCode() 去重。
示例

List<Integer> unique = numbers.stream().distinct().collect(Collectors.toList()); // [1, 2, 3]

关键点

  • 自定义对象去重:需重写 equals()hashCode()

    class User {private Long id;@Overridepublic boolean equals(Object o) { /* 基于id比较 */ }@Overridepublic int hashCode() { /* 基于id生成 */ }
    }
    
  • 性能注意:对大数据集去重可能消耗内存,可结合 limit 分批次处理。


5. sorted():排序

作用:按自然顺序或自定义比较器排序。
示例

List<String> sorted = list.stream().sorted(Comparator.reverseOrder())  // 逆序排序.collect(Collectors.toList());

优化建议

  • 尽早过滤:先 filter 减少待排序数据量。
  • 避免频繁排序:对需要多次排序的场景,考虑转换为有序集合(如 TreeSet)。

6. limit(n) 和 skip(n):分页控制

作用skip 跳过前N个元素,limit 限制返回数量。
示例

List<Integer> result = Stream.iterate(0, n -> n + 1).skip(5)   // 跳过0-4,从5开始.limit(10) // 取5-14.collect(Collectors.toList());

应用场景

  • 分页查询:模拟数据库分页。

    int page = 2, size = 10;
    List<User> users = allUsers.stream().skip((page - 1) * size).limit(size).collect(Collectors.toList());
    
  • 性能注意:对非顺序流(如并行流),skiplimit 可能无法保证预期结果。

  • 3. 终端操作(Terminal Operations)

  • 遍历元素forEach(Consumer<T>)

    list.stream().forEach(System.out::println);
    
  • 收集结果collect(Collector)

    List<String> list = stream.collect(Collectors.toList());
    Set<String> set = stream.collect(Collectors.toSet());
    String joined = stream.collect(Collectors.joining(", "));
    
  • 统计数量count()

    long count = list.stream().filter(s -> s.length() > 3).count();
    
  • 匹配检查

    • anyMatch(Predicate<T>):至少一个元素匹配。
    • allMatch(Predicate<T>):所有元素匹配。
    • noneMatch(Predicate<T>):没有元素匹配。
    boolean hasA = list.stream().anyMatch(s -> s.contains("a"));
    
  • 查找元素

    • findFirst():返回第一个元素(Optional<T>)。
    • findAny():适用于并行流,返回任意元素。
    Optional<String> first = list.stream().findFirst();
    
  • 归约操作reduce(BinaryOperator<T>)

    Optional<Integer> sum = Stream.of(1, 2, 3).reduce(Integer::sum); // 6
    

三、高级用法

1. 分组与分区
  • 分组Collectors.groupingBy()

    Map<Integer, List<String>> groupByLength = list.stream().collect(Collectors.groupingBy(String::length)); // 按字符串长度分组
    
  • 分区Collectors.partitioningBy()

    Map<Boolean, List<String>> partition = list.stream().collect(Collectors.partitioningBy(s -> s.length() > 3)); // 按条件分为两组
    
2. 并行流处理
  • 创建并行流.parallel()parallelStream()

    List<String> result = list.parallelStream().filter(s -> s.length() > 3).collect(Collectors.toList());
    
  • 注意事项

    • 确保操作线程安全(如避免修改共享变量)。
    • 并行流可能不适用于小数据量或复杂中间操作。
3. 原始类型流
  • 避免装箱开销:使用 IntStream, LongStream, DoubleStream

    IntStream.range(1, 5).forEach(System.out::println); // 1, 2, 3, 4
    LongStream.of(10L, 20L).sum();
    

四、实际应用场景示例
1. 数据转换与过滤
// 从用户列表中提取成年用户的姓名
List<String> adultNames = users.stream().filter(user -> user.getAge() >= 18).map(User::getName).collect(Collectors.toList());
2. 统计与汇总
// 计算订单总金额
double totalAmount = orders.stream().mapToDouble(Order::getAmount).sum();
3. 复杂集合处理
// 将多个订单的商品列表合并并去重
Set<String> allProducts = orders.stream().flatMap(order -> order.getProducts().stream()).collect(Collectors.toSet());
4. 分组统计
// 按部门分组统计员工平均工资
Map<String, Double> avgSalaryByDept = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,Collectors.averagingDouble(Employee::getSalary));

五、注意事项与最佳实践
  1. 避免副作用:在流操作中不要修改外部变量,尤其是在并行流中。
  2. 优先使用无状态操作:如 filter, mapsorted, distinct 更高效。
  3. 谨慎使用并行流:仅在数据量大且操作耗时的情况下考虑并行化。
  4. 减少装箱开销:对数值操作使用原始类型流(IntStream 等)。
  5. 合理使用短路操作:如 findFirst(), limit() 可提前终止流处理。

六、与传统循环的对比
场景传统循环Stream 流
简单遍历直接易读代码更简洁,但可能略微性能开销
复杂数据处理需多层嵌套循环,代码冗长链式调用,逻辑清晰
并行处理需手动管理线程和同步通过 .parallel() 自动并行化
函数式编程支持需额外工具类配合原生支持 Lambda 和方法引用

通过掌握 Stream 流的常见用法,可以显著提升代码的可读性和开发效率,尤其在处理集合数据时,能够以更简洁的方式实现复杂的数据操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/81204.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/81204.shtml
英文地址,请注明出处:http://en.pswp.cn/web/81204.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java——设计模式(Design Pattern)

设计模式&#xff08;Design Pattern&#xff09;是软件开发中针对常见问题的经典解决方案&#xff0c;由 GoF&#xff08;Gang of Four&#xff09;在《设计模式&#xff1a;可复用面向对象软件的基础》一书中归纳为23 种模式&#xff0c;分为三大类&#xff1a;创建型模式、结…

python语法学习

1.python的类的定义 class Memory_Manager: 2.__init__ 方法 __init__ 是类的构造方法&#xff0c;用于初始化类的实例。 self 是类实例的引用&#xff0c;用于访问类的属性和方法。 3.方法定义 类中的方法是类的功能实现&#xff0c;通过 def 定义。 4.if __name__ __ma…

如何屏蔽mac电脑更新提醒,禁止系统更新(最新有效方法)

每次打开Mac电脑时&#xff0c;频繁的系统更新提醒可能会对我们的工作和使用体验造成干扰。为了屏蔽这些更新提醒并禁止系统自动更新&#xff0c;我们可以通过修改Hosts文件来实现。以下是详细步骤和方法&#xff0c;帮助你彻底屏蔽macOS的更新提醒。 系统关闭了自动更新也是…

windows10重装ssh无法下载

问题 windows10重装之后&#xff0c;ssh每次都是由于连接的是流量计数的网络无法下载。 解决方法 https://www.cnblogs.com/zhg1016/p/17353348.html

解决 cursor 中不能进入 conda 虚拟环境

【问题】 遇到一个小问题&#xff0c;我创建的conda 环境在 cmd、powershell中都可以激活&#xff0c;但在pycharm、cursor中却不能激活&#xff1f; 看图 cmd中正常&#xff1a; cursor中不正常&#xff1a; 【解决方法】 cursor 中&#xff0c;打开终端&#xff0c;输入&a…

跨平台三维可视化与图形库.VTK图形库.

1. 科学数据可视化 体绘制&#xff08;Volume Rendering&#xff09; 用于医学影像&#xff08;如CT、MRI&#xff09;、气象数据&#xff08;如云层、流体模拟&#xff09;的三维渲染&#xff0c;支持透明度、光照和颜色映射。 等值面提取&#xff08;Iso-Surfacing&#xff…

【萤火工场GD32VW553-IOT开发板】ADC电压的LabVIEW采集

【萤火工场GD32VW553-IOT开发板】ADC电压的LabVIEW采集 &#x1f50b; 本文介绍了萤火工场 GD32VW553-IOT 开发板通过串口中断查询的方式采集 ADC 电压及温度转换数据&#xff0c;并进一步结合LabVIEW上位机实现数据自动采集和实时监测的项目设计。 项目介绍 串口中断查询&a…

视频监控管理平台EasyCVR结合AI分析技术构建高空抛物智能监控系统,筑牢社区安全防护网

高空抛物严重威胁居民生命安全与公共秩序&#xff0c;传统监管手段存在追责难、威慑弱等问题。本方案基于EasyCVR视频监控与AI视频分析技术&#xff08;智能分析网关&#xff09;&#xff0c;构建高空抛物智能监控系统&#xff0c;实现24小时实时监测、智能识别与精准预警&…

Python----循环神经网络(LSTM:长短期记忆网络)

一、RNN的长期依赖问题 可以看到序列越长累乘项项数越多&#xff0c;项数越多就可能会让累乘结果越小&#xff0c;此时对于W 的更新就取决于第一项或者是前几项&#xff0c;也就是RNN模型会丢失很多较远时刻的信息而 更关注当前较近的几个时刻的信息&#xff0c;即没有很好的长…

【跨端框架检测】使用adb logcat检测Android APP使用的跨端框架方法总结

目录 Weex 跨端框架使用了uni-app的情况区分使用了uni-app还是Weex 判断使用了Xamarin判断使用了KMM框架判断使用了 ​​Ionic 框架判断使用了Cordova框架判断使用了Capacitor 框架使用了React Native框架使用了QT框架使用了Cocos框架使用了Electron 框架使用了flutter 框架使用…

以加减法计算器为例,了解C++命名作用域与函数调用

************* C topic: 命名作用域与函数调用 ************* The concept is fully introducted in the last artical. Please refer to 抽象&#xff1a;C命名作用域与函数调用-CSDN博客 And lets make a calculator to review the basic structure in c. 1、全局函数 A…

AIGC小程序项目

一、文生文功能 &#xff08;1&#xff09;前端部分 使用 Pinia 状态管理库创建的聊天机器人消息存储模块&#xff0c;它实现了文生文&#xff08;文本生成文本&#xff09;的核心逻辑。 1.Pinia状态管理 这个模块管理两个主要状态&#xff1a; messages&#xff1a;存储所…

Axios中POST、PUT、PATCH用法区别

在 Axios 中&#xff0c;POST、PUT 和 PATCH 是用于发送 HTTP 请求的三种不同方法&#xff0c;它们的核心区别源自 HTTP 协议的设计语义。以下是它们的用法和区别&#xff1a; 1. POST 语义&#xff1a;用于创建新资源。 特点&#xff1a; 非幂等&#xff08;多次调用可能产生…

[爬虫知识] Cookie与Session

相关实战案例&#xff1a;[爬虫实战] 爬取小说标题与对应内容 相关爬虫专栏&#xff1a;JS逆向爬虫实战 爬虫知识点合集 爬虫实战案例 一、引入场景 在http协议中&#xff0c;浏览器是无状态&#xff08;即无记忆&#xff09;的&#xff0c;对于请求与响应的产生数据&#…

怎样改变中断优先级?

在STM32中改变中断优先级可以通过STM32CubeMX配置和代码中设置两种方式来实现。以下以STM32F1系列为例进行说明: 使用STM32CubeMX配置 打开工程:在STM32CubeMX中打开你的工程。进入NVIC配置:在Pinout & Configuration选项卡中,点击NVIC进入中断向量控制器配置界面。选…

科学计算中的深度学习模型精解:CNN、U-Net 和 Diffusion Models

关键要点 模型概述:卷积神经网络(CNN)、U-Net 和 Diffusion Models 是深度学习中的核心模型,广泛应用于科学计算任务,如偏微分方程(PDE)求解、图像分割和数据生成。科学计算应用:CNN 可用于高效求解 PDEs,U-Net 擅长医学图像分割和材料分析,Diffusion Models 在生成合…

解决Docker无法拉取镜像问题:Windows系统配置镜像加速全指南

问题背景 在使用 Docker 时&#xff0c;你是否遇到过以下报错&#xff1f; Unable to find image ‘mysql:latest’ locally docker: Error response from daemon: Get “https://registry-1.docker.io/v2/”: dial tcp 128.242.250.155:443: i/o timeout. 这类问题通常是由于…

Spring AI 使用教程

Spring AI 使用教程&#xff08;2025年5月24日更新&#xff09; 一、环境搭建与项目初始化 创建Spring Boot项目 使用IDEA或Spring Initializr创建项目&#xff0c;选择JDK 17或更高版本&#xff08;推荐21&#xff09;。勾选依赖项&#xff1a;Spring Web、Lombok&#xff0c;…

iOS 直播特殊礼物特效实现方案(Swift实现,超详细!)

特殊礼物特效是提升直播互动体验的关键功能&#xff0c;下面我将详细介绍如何在iOS应用中实现各种高级礼物特效。 基础特效类型 1.1 全屏动画特效 class FullScreenAnimationView: UIView {static func show(with gift: GiftModel, in view: UIView) {let effectView FullS…

分布式事务之Seata

概述 Seata有四种模式 AT模式&#xff1a;无侵入式的分布式事务解决方案&#xff0c;适合不希望对业务进行改造的场景&#xff0c;但由于需要添加全局事务锁&#xff0c;对影响高并发系统的性能。该模式主要关注多DB访问的数据一致性&#xff0c;也包括多服务下的多DB数据访问…