封面图上流动的「Stream」字样,正是 Java 8 以来最革命性的特性之一!你是否还在写冗长的 for 循环遍历集合?是否为过滤、排序、聚合数据写一堆重复代码?Stream 流的出现,以声明式编程风格将复杂的集合操作浓缩为一行代码,不仅可读性更强,还能轻松实现并行处理。本文将从 Stream 的核心概念(中间操作 / 终止操作)讲起,结合 10 + 实战案例(过滤去重、分组统计、链式调用),带你吃透 Stream 流的精髓,让代码更优雅、更高效!


Stream API  万物皆可一行代码
Stream专门针对集合的各种操作提供各种非常便利,简单,高效的API,
Stream API主要是通过Lambda表达式完成,极大的提高了程序的效率和可读性,
同时Stram API中自带的并行流使得并发处理集合的门槛再次降低,使用Stream API编程无需多写

怎样使用Stream流?

1. 获取流-->  2. 对流进行操作-->3.结束对流的操作

获取流的方式

集合类可通过 Collection.stream()Collection.parallelStream() 获取流;

数组可通过 Arrays.stream(T[] array)Stream.of() 转换。

IO 相关流如 Files.walk()BufferedReader.lines() 也可生成流。


中间操作(Intermediate Operations)

中间操作返回新流,支持链式调用,操作延迟执行(lazy)。

映射操作

  • map:元素一对一转换。
    List<String> names = students.stream().map(Student::getName).collect(Collectors.toList());
    
  • flatMap:扁平化多维结构。
    List<String> words = lines.stream().flatMap(line -> Arrays.stream(line.split(" "))).collect(Collectors.toList());
    

过滤与去重

  • filter:保留符合谓词的元素。
    List<Student> adults = students.stream().filter(s -> s.getAge() > 18).collect(Collectors.toList());
    
  • distinct:去除重复元素(依赖 equals 方法)。

排序与裁剪

  • sorted:自然排序或自定义比较器。

在Java流(Stream) API中,sorted方法用于对流中的元素进行排序操作。它支持两种重载形式,可以根据需要选择无参数或传入自定义比较器(Comparator)。下面我将逐步解释其用法,并提供真实可靠的示例代码,帮助您理解如何高效实现排序。

1. 无参数sorted方法
  • 当调用sorted()方法而不传递任何参数时,要求流中的元素必须实现Comparable<T>接口。这适用于元素类已经定义了自然排序顺序的情况。
  • 示例:如果元素类(如String或自定义类)实现了Comparable,则可以直接使用。
    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    names.stream().sorted()  // 依赖String的Comparable实现.forEach(System.out::println);
    
    输出结果将是按字母顺序排序的元素:Alice, Bob, Charlie
2. 带Comparator参数的sorted方法
  • 方法签名:Stream<T> sorted(Comparator<? super T> comparator)

  • 这允许您传入一个自定义比较器来定义排序规则,特别适用于元素类未实现Comparable或需要特定排序逻辑的场景。

  • 使用lambda表达式可以简洁地定义比较器。

    • 示例:基于对象的属性(如年龄)排序。
      List<Student> students = Arrays.asList(new Student("Alice", 20),new Student("Bob", 18),new Student("Charlie", 22)
      );// 使用lambda表达式排序:按年龄从小到大
      students.stream().sorted((s1, s2) -> Integer.compare(s1.getAge(), s2.getAge())).forEach(System.out::println);
      
      输出:按年龄升序显示学生信息(如Bob(18), Alice(20), Charlie(22))。
  • 更推荐使用Comparator的工厂方法(如Comparator.comparingInt),以提高代码可读性和健壮性。

    • 示例:使用Comparator.comparingInt优化排序。
      students.stream().sorted(Comparator.comparingInt(Student::getAge))  // 等价于lambda,但更简洁.forEach(System.out::println);
      
      输出与上述相同,但代码更易于维护。
3. 注意事项和最佳实践
  • 性能考虑sorted方法是一个有状态操作,可能影响流性能。对于大数据集,建议在排序前使用parallelStream()(如果线程安全)。
  • 降序排序:可以通过Comparator.reversed()实现降序。
    students.stream().sorted(Comparator.comparingInt(Student::getAge).reversed()).forEach(System.out::println);
    
    输出:按年龄降序(如Charlie(22), Alice(20), Bob(18))。
  • 多字段排序:使用Comparator.thenComparing实现复合排序。
    students.stream().sorted(Comparator.comparing(Student::getName).thenComparingInt(Student::getAge)).forEach(System.out::println);
    
    先按名字排序,再按年龄排序。
  • limit/skip:截取前 N 项或跳过前 N 项。

调试辅助

  • peek:遍历元素但不终结流,常用于调试。
    students.stream().peek(s -> System.out.println("Processing: " + s.getName())).collect(Collectors.toList());
    

终结操作(Terminal Operations)

终结操作触发流处理并返回结果或副作用。

遍历与聚合

  • forEach:遍历元素。
    students.stream().forEach(System.out::println);
    
  • count:统计元素数量。
    long count = students.stream().count();
    
  • min/max:需传入比较器。
    Optional<Student> oldest = students.stream().max(Comparator.comparingInt(Student::getAge));
    

匹配与查找

  • anyMatch/allMatch/noneMatch:检查元素是否匹配条件。
    boolean hasAdult = students.stream().anyMatch(s -> s.getAge() > 18);
    
  • findFirst/findAny:返回首个或任意元素(并行流中效率更高)。

归约与收集

2. 使用 Collectors 简化操作

Collectors 类提供了许多内置转换器,如 toList()toSet() 等,可以直接传入 collect 方法。例如:

3. groupingBy 分组操作

groupingBy 类似于 SQL 中的 GROUP BY,用于按指定条件分组元素。它有多个参数版本:

4. toMap 转换操作

toMap 用于将流转换为 Map,需指定键和值的映射函数。例如:

// 将学生列表转换为 Map<年龄, 学生对象>
Map<Integer, Student> map = students.stream().collect(Collectors.toMap(Student::getAge, s -> s));

5. 基本数据类型流的限制

对于基本数据类型流(如 IntStreamLongStreamDoubleStream),没有 collect 方法。这是因为基本类型涉及装箱(boxing)和拆箱(unboxing)操作,Java SDK 未将其集成到流收集机制中。替代方案是:

  • reduce:聚合元素。
    Optional<Integer> totalAge = students.stream().map(Student::getAge).reduce(Integer::sum);
    
  • collect:转换为集合或分组。
  • collect 是 Java Stream API 中的一个终端操作,用于将流中的元素收集到一个容器中(如集合或映射)。下面我将基于您提供的信息,逐步解释 collect 的使用方法、常见场景和注意事项,确保内容真实可靠(基于 Java 8 及以上版本的规范)。

    1. collect 方法的基本签名

    collect 方法有两个主要重载形式:

  • 第一个重载:接受三个参数(supplier、accumulator 和 combiner),用于自定义收集逻辑。
    <R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner);
    
    • supplier:提供一个新容器(如 ArrayList::new)。
    • accumulator:将元素添加到容器中(如 List::add)。
    • combiner:在并行流中合并多个容器(如 List::addAll)。
  • 第二个重载:接受一个 Collector 对象,简化常见操作。
    <R, A> R collect(Collector<? super T, A, R> collector);
    
    通常,我们使用 Collectors 工具类中的静态方法作为参数,因为它是更简洁的方式。
  • 转换为列表:将流元素收集到 List 中。
    List<Integer> list = integers.stream().collect(Collectors.toList());
    
    默认使用 ArrayList
  • 转换为集合:将流元素收集到 Set 中。
    Set<Integer> set = integers.stream().collect(Collectors.toSet());
    
    默认使用 HashSet
  • 单参数版本:按分类函数分组,返回 Map
    // 按学生年龄分组,返回 Map<Integer, List<Student>>
    Map<Integer, List<Student>> map = students.stream().collect(Collectors.groupingBy(Student::getAge));
    
    默认使用 HashMap 作为容器。
  • 多参数版本:支持自定义容器和下游收集器。
    • 两个参数:指定分类函数和下游收集器(如 toList())。
    • 三个参数:添加容器类型(如 TreeMap::new)。 例如,您提到的例子:按年龄分组,但只收集学生姓名而非整个对象。
    // 按年龄分组,每组存储学生姓名列表
    Map<Integer, List<String>> map = students.stream().collect(Collectors.groupingBy(Student::getAge,Collectors.mapping(Student::getName, Collectors.toList())));
    
    这里:
    • 第一个参数 Student::getAge 是分类依据。
    • 第二个参数 Collectors.mapping(...) 是下游收集器,其中 mapping 将每个学生映射到姓名,再用 toList() 收集为列表。 如果省略容器参数,默认仍为 HashMap
  • 第一个参数 Student::getAge 定义键(key)。
  • 第二个参数 s -> s 定义值(value),这里直接使用学生对象。 注意事项
  • 如果键重复,会抛出 IllegalStateException。解决方法是添加第三个参数(合并函数),如 (oldValue, newValue) -> oldValue 保留第一个值。
  • 默认使用 HashMap,但可以通过第四个参数指定其他 Map 实现(如 TreeMap::new)。
  • 使用 toArray() 方法转换为数组。
    int[] array = intStream.toArray();
    
  • 或者,先将流转换为对象流(如 boxed()),再使用 collect
    List<Integer> list = intStream.boxed().collect(Collectors.toList());
    
  • 特殊转换
  • toArray:转为数组,可指定类型。
    Student[] array = students.stream().toArray(Student[]::new);
    

并行流注意事项

通过 parallelStream() 可启用并行处理,但需确保操作无状态且避免共享变量。以下场景适合并行流:

  • 数据量较大且处理耗时。
  • 任务可独立分片(如过滤、映射)。
List<Student> adults = students.parallelStream().filter(s -> s.getAge() > 18).collect(Collectors.toList());

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

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

相关文章

前端笔记2025

前端 与后端交互 下载后端接口的文件时&#xff0c;若是二进制&#xff0c;需要在请求中添加responseType: ‘blob’ 例如 axios.get(‘http://127.0.0.1:8612/api/daily/report/tdjzxz?selectedMonth2022-06’, { headers: { ‘Accesstoken’: ‘f033b94655f84386a0c112b41…

【LeetCode每日一题】226. 翻转二叉树 101. 对称二叉树

每日一题226. 翻转二叉树题目总体思路代码101. 对称二叉树题目总体思路代码知识点2025.9.5226. 翻转二叉树 题目 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&am…

【RNN-LSTM-GRU】第三篇 LSTM门控机制详解:告别梯度消失,让神经网络拥有长期记忆

深入剖析LSTM的三大门控机制&#xff1a;遗忘门、输入门、输出门&#xff0c;通过直观比喻、数学原理和代码实现&#xff0c;彻底理解如何解决长期依赖问题。1. 引言&#xff1a;为什么需要LSTM&#xff1f;在上一篇讲解RNN的文章中&#xff0c;我们了解到​​循环神经网络&…

残差去噪扩散模型

论文题目:Residual Denoising Diffusion Models(残差去噪扩散模型) 会议:CVPR2024 摘要:残差去噪扩散模型(RDDM)是一种新的双重扩散过程,它将传统的单一去噪扩散过程解耦为残差扩散和噪声扩散。这种双重扩散框架通过引入残差,将基于去噪的扩散模型扩展为一种统一的、可…

MySQL与ES索引区别

MySQL与ES索引区别 MySQL索引像字典目录&#xff0c;ES索引更像整个图书馆的书籍分类系统。 关键限制&#xff1a;MySQL单表索引大小影响写性能&#xff0c;ES的分片数创建后不能改。 比如MySQL的“行”对应ES的“文档”&#xff0c;MySQL的“表”类似ES的“索引”概念。 MySQL…

vue3图标终极方案【npm包推荐】vue3-icon-sui(含源码详解)

简介 为彻底实现 vue3 项目图标自由&#xff0c;特开发此 npm包 vue3-icon-sui&#xff0c;全品类图标&#xff0c;通通支持&#xff01; iconify 图标svg 图标font-class 图标 安装 npm i vue3-icon-sui -S使用 按需导入 任意页面中 import myIcon from "vue3-icon-su…

redis----持久化

Redis 提供了两种主要的持久化机制&#xff0c;用于将内存中的数据保存到磁盘&#xff0c;以防止服务器重启或故障导致数据丢失。这两种机制分别是 RDB&#xff08;Redis Database&#xff09;和 AOF&#xff08;Append Only File&#xff09;。1. RDB 持久化RDB 是 Redis 默认…

Docker快速部署Mongodb主副本集实践

系列文章目录 第一章 Mongodb的主副本集 文章目录系列文章目录前言一、Mongodb基础介绍数据库&#xff08;Database&#xff09;集合&#xff08;Collection&#xff09;文档&#xff08;Document&#xff09;BSON&#xff08;Binary JSON&#xff09;_id&#xff08;主键&…

FC平台安装Windows Server2016并连接V6存储

创建 windows server2016 上传ISO创建虚拟机安装OS 加载光盘挂载成功之后&#xff0c;重启虚拟机重启之后VNC登录即可。在FC上安装windows&#xff0c;安装完成后&#xff0c;必须安装tools工具&#xff0c;不然没有虚拟网卡&#xff0c;无法配置ip地址。Windows主机安装toolsW…

农业XR数字融合工作站,赋能农业专业实践学习

随着数字技术与农业的深度融合&#xff0c;农业专业XR数字融合工作站为农业专业学生提供了沉浸式、交互式的学习体验。农业专业XR数字融合工作站作为集PC、VR、MR技术于一体的软硬件集成平台&#xff0c;通过虚拟仿真、数字孪生等技术手段&#xff0c;有效解决了传统农业教育中…

积分球的使用——简易版

这篇写的比较杂。积分球的功能积分球——测量灯具等光源的总光通量、光效、色温、显色指数等参数。使用方法1.开启积分球系统&#xff08;探测器、光度计、光谱仪&#xff09;&#xff0c;充分预热&#xff08;15-30分钟&#xff09;&#xff0c;使得电子设备稳定&#xff0c;减…

[光学原理与应用-435]:晶体光学 - 晶体的结构-基元/原胞/晶胞/点阵

晶体的结构可通过基元、原胞、晶胞和点阵四个核心概念进行系统描述&#xff0c;它们共同揭示了晶体中原子排列的周期性与对称性规律&#xff0c;具体如下&#xff1a;1. 基元&#xff08;Structure Motif&#xff09;定义&#xff1a;基元是晶体中重复排列的最小结构单元&#…

电脑音频录制 | 系统麦克混录 / 系统声卡直录 | 方法汇总 / 常见问题

注&#xff1a;本文为 “电脑音频录制 ” 相关合辑。 英文引文&#xff0c;机翻未校。 未整理去重&#xff0c;如有内容异常&#xff0c;请看原文。 How to Record Computer Audio in 6 Free Ways 如何用 6 种免费方式录制电脑音频 Sponsored by EaseUS Nov 28, 2023 4:34 a…

2025高教社国赛数学建模竞赛B题完整参考论文(含模型和代码)

2025国赛数学建模竞赛B题完整参考论文 目录 一、 问题重述 1.1 问题背景 1.2 问题回顾与分析 二、 模型假设 三、 符号说明 四、 问题求解与分析 4.1数据预处理 4.2 问题1求解与分析 4.2.1 问题1分析 4.2.2 问题1建模与求解 4.2.3 问题1结果与分析 4.3 问题2求解与分…

OpenSSL 1.0.1e 下载解压和运行方法(小白适用 附安装包)​

openssl-1.0.1e.zip​ 是 OpenSSL 加密工具包的一个旧版本&#xff08;发布于 2013 年左右&#xff09;的 ​源代码压缩包&#xff0c;文件格式是 ZIP 压缩格式。 一、下载与解压 ​下载文件​ 假如你已经有了 openssl-1.0.1e.zip 这个压缩包&#xff0c;就跳过这步。 如果没有…

MapStruct详解

提到属性拷贝&#xff0c;首先想到的BeanUtils。 先简单的回忆下BeanUtils&#xff0c;处理Java Bean之间的属性拷贝&#xff1b;不过由于它是通过反射来拷贝属性&#xff0c;在数据量大一些的时候性能会降低&#xff1b; 且在安全方面也会比较弱&#xff1b; MapStruct是编译期…

8.FC平台模块梳理

文章目录8.FC平台模块梳理8.1. 内存复用技术特点应用价值8.2. 虚拟机启用策略8.3. NUMA8.4. HA高可用8.5. 故障和响应策略8.6. DRS 和 DPM8.7. IMC8.FC平台模块梳理 8.1. 内存复用 内存共享内存交换内存气泡 内存共享&#xff1a;多台虚拟机共享数据内容相同的内存页。内存交换…

贪心算法应用:DNA自组装问题详解

JAVA中的贪心算法应用&#xff1a;DNA自组装问题详解 1. DNA自组装问题概述 DNA自组装(DNA Self-Assembly)是分子计算和纳米技术中的一个重要问题&#xff0c;它利用DNA分子的互补配对特性&#xff0c;通过精心设计DNA序列&#xff0c;使其自发地组装成预定的纳米结构。在计算机…

数据湖如何打造统一存储与处理方案(结构化数据、半结构化数据和非结构化数据)

目录 1. 数据湖的“包容哲学”:为什么需要统一方案? 数据湖的核心诉求 案例:零售企业的痛点 2. 存储层设计:给数据找个舒适的家 分区与分层存储 选择存储格式 案例:Parquet的威力 云存储的选择 3. 元数据管理:给数据湖装上“导航仪” 元数据管理的核心组件 主流…

AUTOSAR进阶图解==>AUTOSAR_SWS_TTCANDriver

TTCAN驱动器详细规范 AUTOSAR TTCAN Driver Specification with Enhanced Visual Documentation目录 1. 概述2. TTCAN控制器状态机3. TTCAN模块架构4. TTCAN时间触发操作序列5. TTCAN错误处理流程6. 总结 1. 概述 TTCAN&#xff08;Time-Triggered CAN&#xff09;驱动器是AU…