Java 8 中的 Stream API,用于处理集合数据

news2024/11/18 7:47:24

Java 8 引入了 Stream API,使得处理集合数据变得更加简洁和高效。Stream API 允许开发者以声明式编程风格操作数据集合,而不是使用传统的迭代和条件语句。

一、基本概念

1.1 什么是 Stream

Stream 是 Java 8 中的一个新抽象,它允许对集合数据执行各种复杂的操作,例如过滤、映射、规约、收集等。Stream 不存储数据,而是从集合或其他数据源(如数组、I/O channel 等)中获取数据并进行操作。

Stream 的主要特点包括:

  • 无存储:Stream 不存储数据,只是对数据进行操作。
  • 函数式编程:使用 lambda 表达式进行操作,使代码更简洁。
  • 延迟执行:Stream 操作是懒加载的,只有在需要结果时才会执行。
  • 可组合性:多个 Stream 操作可以连成一串操作链,形成一系列的转换。

1.2 Stream 的生命周期

Stream 的操作可以分为三类:

  • :创建 Stream 的数据源,例如集合、数组或 I/O channel。
  • 中间操作:返回新的 Stream 的操作,例如过滤、映射。
  • 终端操作:产生结果或副作用的操作,例如收集、计算。

一个 Stream 的生命周期可以简单描述为:

  1. 创建 Stream。
  2. 中间操作。
  3. 终端操作。

二、Stream API 的基本操作

2.1 创建 Stream

Stream 可以通过以下几种方式创建:

  • 从集合
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
  • 从数组
String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);
  • 从值
Stream<String> stream = Stream.of("a", "b", "c");
  • 从文件
Stream<String> stream = Files.lines(Paths.get("path/to/file.txt"));

2.2 中间操作

中间操作返回一个新的 Stream,它们是延迟执行的,只有在终端操作执行时才会实际进行计算。常用的中间操作包括:

2.2.1 filter

filter 用于对 Stream 中的元素进行过滤,只保留满足条件的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0);
2.2.2 map

map 用于将 Stream 中的每个元素映射到另一个元素。

List<String> words = Arrays.asList("Java", "Stream", "API");
Stream<Integer> wordLengths = words.stream().map(String::length);
2.2.3 flatMap

flatMap 用于将 Stream 中的每个元素映射到一个新的 Stream,并将这些新 Stream 合并成一个 Stream。

List<List<String>> listOfLists = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
Stream<String> flatStream = listOfLists.stream().flatMap(Collection::stream);
2.2.4 distinct

distinct 用于去除 Stream 中的重复元素。

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
Stream<Integer> distinctNumbers = numbers.stream().distinct();
2.2.5 sorted

sorted 用于对 Stream 中的元素进行排序,可以传递一个比较器。

List<String> words = Arrays.asList("Java", "Stream", "API");
Stream<String> sortedWords = words.stream().sorted();

2.3 终端操作

终端操作会触发 Stream 的计算,并生成结果或副作用。常用的终端操作包括:

2.3.1 forEach

forEach 用于对 Stream 中的每个元素执行一个动作。

List<String> words = Arrays.asList("Java", "Stream", "API");
words.stream().forEach(System.out::println);
2.3.2 toArray

toArray 用于将 Stream 中的元素收集到一个数组中。

List<String> words = Arrays.asList("Java", "Stream", "API");
String[] array = words.stream().toArray(String[]::new);
2.3.3 reduce

reduce 用于将 Stream 中的元素通过一个关联函数组合起来,生成一个值。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(0, Integer::sum);
2.3.4 collect

collect 用于将 Stream 中的元素收集到一个容器中,例如 List、Set 或 Map。

List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> upperCaseWords = words.stream().map(String::toUpperCase).collect(Collectors.toList());
2.3.5 count

count 用于返回 Stream 中的元素数量。

List<String> words = Arrays.asList("Java", "Stream", "API");
long count = words.stream().count();
2.3.6 findFirstfindAny

findFirst 用于返回 Stream 中的第一个元素(如果存在)。

List<String> words = Arrays.asList("Java", "Stream", "API");
Optional<String> first = words.stream().findFirst();

findAny 用于返回 Stream 中的任意一个元素(如果存在),常用于并行流。

List<String> words = Arrays.asList("Java", "Stream", "API");
Optional<String> any = words.stream().findAny();
2.3.7 anyMatchallMatchnoneMatch

这三个操作用于检查 Stream 中是否有任意、所有或没有元素满足指定的条件。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0);
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
boolean noneNegative = numbers.stream().noneMatch(n -> n < 0);

三、并行流

Java 8 提供了并行流,可以充分利用多核处理器的优势。只需调用 parallelStream 方法即可创建一个并行流。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream().reduce(0, Integer::sum);

并行流通过将数据分成多个子流,并在不同的 CPU 核心上并行处理这些子流,然后再合并结果,来提高处理速度。需要注意的是,并行流适合于无状态和无副作用的操作,使用时需小心处理共享变量和同步问题。

四、Stream API 的最佳实践

4.1 使用 Lambda 表达式

Stream API 通常与 lambda 表达式一起使用,使代码更加简洁和易读。例如:

List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> upperCaseWords = words.stream().map(word -> word.toUpperCase()).collect(Collectors.toList());

4.2 避免使用修改状态的中间操作

Stream 操作应该是无副作用的,即不应修改外部状态。以下示例展示了一个错误的用法:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> results = new ArrayList<>();
numbers.stream().forEach(n -> results.add(n * 2));  // 这样做是错误的

正确的做法是使用终端操作 collect

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> results = numbers.stream().map(n -> n * 2).collect(Collectors.toList());

4.3 利用方法引用

方法引用可以使代码更加简洁。例如,使用方法引用替代 lambda 表达式:

List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> upperCaseWords = words.stream().map(String::toUpperCase).collect(Collectors.toList());

4.4 避免使用并行流进行小任务

并行流在处理大量数据或复杂计算时非常高效,但对于小任务,启动并行计算的开销可能会大于收益。因此,在数据量较小或计算较简单的情况下,优先使用顺序流。

4.5 避免在终端操作之前调用 findAny

在终端操作之前调用 findAny 会导致流的中间操作链被截断,进而无法正确执行后续的操作。例如:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = numbers.stream().filter(n -> n % 2 == 0).findAny(); // 这样做会中断流

应将 findAny 用作终端操作:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = numbers.stream().filter(n -> n % 2 == 0).findAny();

4.6 使用 collect 进行结果收集

collect 是一个强大的终端操作,可以将流中的元素收集到各种容器中。例如,收集到 List:

List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> wordList = words.stream().collect(Collectors.toList());

4.7 使用 Collectors 进行复杂收集操作

Collectors 提供了多种收集器,可以进行复杂的结果收集。例如,收集到 Map:

List<String> words = Arrays.asList("Java", "Stream", "API");
Map<Integer, List<String>> wordLengthMap = words.stream().collect(Collectors.groupingBy(String::length));

4.8 使用 Optional 处理可能的空值

Stream API 中的某些终端操作会返回 Optional,例如 findFirstfindAny。使用 Optional 可以避免空指针异常:

List<String> words = Arrays.asList("Java", "Stream", "API");
Optional<String> firstWord = words.stream().findFirst();
firstWord.ifPresent(System.out::println);

Java 8 的 Stream API 为集合数据的处理提供了一种高效、简洁的方式。通过理解和掌握 Stream 的基本概念、常用操作以及最佳实践,可以大大提高 Java 开发的生产力和代码质量。

Stream API 不仅支持顺序流,还支持并行流,使得在多核环境下处理大量数据变得更加高效。在实际开发中,合理使用 Stream API 可以显著提升代码的可读性和稳定性。

黑马程序员免费预约咨询

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java学习笔记(六):Array List、学生管理系统、学生管理系统升级版

目录 一、ArrayList 1.1集合和数组的优势对比&#xff1a; 1.2 ArrayList类概述 1.3 ArrayList类常用方法 1.3.1 构造方法 1.3.2 成员方法 1.4 ArrayList存储字符串并遍历 1.5 ArrayList存储学生对象并遍历 1.6 查找用户的索引 1.7 添加手机对象并返回要求的数据 二…

用 Notepad++ 写 Java 程序

安装包 百度网盘 提取码&#xff1a;6666 安装步骤 双击安装包开始安装。 安装完成&#xff1a; 配置编码 用 NotePad 写 Java 程序时&#xff0c;需要设置编码。 在 设置&#xff0c;首选项&#xff0c;新建 中进行设置&#xff0c;可以对每一个新建的文件起作用。 Note…

【Flutter】 TextField限制长度时, 第三方手写输入法、ios原始拼音输入法输入被吞问题

问题描述 TextField限制长度时&#xff0c; 当你的输入字符长度已经到了最大值-1时&#xff0c;使用第三方手写输入法或者ios原生拼音输入法输入liang&#xff08;什么拼音都行&#xff0c;这里只是举例&#xff09;&#xff0c;输到i那么li都会消失。 原因分析 这是因为第三…

nginx配置WebSocket参数wss连接

目录 一、原文连接 二、 配置参数 三、实践 四、重启nginx 五、连接websocket 一、原文连接 nginx配置websocket支持wss-腾讯云开发者社区-腾讯云 二、 配置参数 map $http_upgrade $connection_upgrade { default upgrade; close; } upstream websocket { se…

PostgreSQL基础(九):PostgreSQL的事务介绍

文章目录 PostgreSQL的事务介绍 一、什么是ACID&#xff08;常识&#xff09; 二、事务的基本使用 三、保存点&#xff08;了解&#xff09; PostgreSQL的事务介绍 一、什么是ACID&#xff08;常识&#xff09; 在日常操作中&#xff0c;对于一组相关操作&#xff0c;通常…

基于t-SNE的泰坦尼克号数据集降维

目录 1. 作者介绍2. 算法介绍2.1 t-SNE介绍2.2.SNE基本原理2.3.拥挤问题2.4.t-SNE基本原理2.5.t-SNE算法过程 3. 泰坦尼克号数据集降维实验3.1.数据集介绍3.2 任务介绍3.3 代码实现3.4 实验结果 参考连接 1. 作者介绍 刘方星&#xff0c;男&#xff0c;西安工程大学电子信息学…

vue3 监听器,组合式API的watch用法

watch函数 在组合式 API 中&#xff0c;我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数 watch(ref,callback&#xff08;newValue,oldValue&#xff09;&#xff0c;option:{}) ref:被监听的响应式量&#xff0c;可以是一个 ref (包括计算属性)、一个响应式…

大型零售企业总部到分公司数据发放,有没有更优化的方案?

大型零售企业在市场经济中扮演重要角色&#xff0c;是保证基础商品生产、流通和供给的重要一环。随着企业发展&#xff0c;很多大型零售企业都会在全国、乃至全球各地开设分公司&#xff0c;用以降低生产和运营成本&#xff0c;更好地提供本地化服务。 为了保证总部与分公司间信…

【C++ | 拷贝构造函数】一文了解C++的 拷贝(复制)构造函数

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-06-07 2…

Linux.软件操作

1.yum 命令 要连网 2.systemctl 命令控制软件的启动和关闭 3.ln 创建软连接 使用cat来找本体&#xff0c;看看链接生不生效 4.date 命令查看系统时间 格式化的时候可以用双引号把他们引出来 -d 对时间进行修改 修改时区 自动校准 手动校准 5.ifconfig 查看本机的ip地址 6.h…

SOA主要协议和规范

Web服务作为实现SOA中服务的最主要手段。首先来了解Web Service相关的标准。它们大多以“WS-”作为名字的前缀&#xff0c;所以统称“WS-*”。Web服务最基本的协议包括UDDI、WSDL和SOAP&#xff0c;通过它们&#xff0c;可以提供直接而又简单的Web Service支持&#xff0c;如图…

《机器学习特征提取》

书籍&#xff1a;Building Feature Extraction with Machine Learning: Geospatial Applications 作者&#xff1a;Bharath.H. Aithal&#xff0c;Prakash P.S. 出版&#xff1a;CRC Press 书籍下载-《机器学习特征提取》这是一本面向专业人士和研究生的实用指南&#xff0c…

Docker|了解容器镜像层(1)

引言 容器非常神奇。它们允许简单的进程表现得像虚拟机。在这种优雅的底层是一组模式和实践&#xff0c;最终使一切运作起来。在设计的根本是层。层是存储和分发容器化文件系统内容的基本方式。这种设计既出人意料地简单&#xff0c;同时又非常强大。在今天的帖子[1]中&#xf…

PS初级|写在纸上的字怎么抠成透明背景?

前言 上一次咱们讲了很多很多很多的抠图教程&#xff0c;这次继续。。。最近有小伙伴问我&#xff1a;如果是写在纸上的字&#xff0c;要怎么把它抠成透明背景。 这个其实很简单&#xff0c;直接来说就是选择通道来抠。但有一点要注意的是&#xff0c;写在纸上的字&#xff0…

elementui Menu 二级菜单 min-width修改无效

原因&#xff1a;可能是生成的二级菜单样式里面没有带特定的hash属性 而vue代码里面样式里带了 scoped生成的样式有改样式选择器 从而无法成功选择 解决&#xff1a;让样式可以全局选择 不带属性选择器 单文件组件 CSS 功能 | Vue.js :global(.el-menu--vertical .el-menu--p…

【Web API DOM11】节点操作

一&#xff1a;DOM节点 1 什么是DOM节点 DOM树里每一个内容都称为节点 2 DOM节点分类 元素节点 属性节点&#xff1a;a标签的href、img标签的src等 文本节点&#xff1a;标签中的文字 上图为整个DOM树&#xff0c;每个标签、以及标签属性、文本内容构成了DOM树 二&#…

码蹄集部分题目(2024OJ赛18期;并查集+ST表+贪心)

1&#x1f40b;&#x1f40b;史莱姆融合&#xff08;钻石&#xff1b;并查集&#xff09; 时间限制&#xff1a;1秒 占用内存&#xff1a;128M &#x1f41f;题目描述 &#x1f41f;题目思路 这道题目使用并查集&#xff0c;同一集合的所有元素的最顶上的祖父节点是统一的。…

[NOVATEK] NT96580行车记录仪功能学习笔记

一、u-Boot升级灯 运行u-Boot程序时LED灯闪烁,找到运行过程中一直在运行的函数在里面进行LED引脚电平的翻转 宏定义 Z:\SunFan\AHD580\pip\na51055_PIP\BSP\u-boot\include\configs\nvt-na51055-evb.h Z:\SunFan\AHD580\pip\na51055_PIP\BSP\u-boot\drivers\mtd\nvt_flash_…

【BOM02】本地存储

一&#xff1a;什么是本地存储 数据存储在用户浏览器中&#xff0c;用户设置、读取方便&#xff0c;同时页面刷新时不会丢失数据。存储在浏览器中数据约5M&#xff0c;分为sessionStorage和localStorage两种存储方式 二&#xff1a;localStorage存储 作用 将数据永久存储在…

idm2024最新完美破解版免费下载 idm绿色直装版注册机免费分享 idm永久激活码工具

IDM 2024破解版重新开发了调度程序和MMS协议支持、重新设计和增强的下载引擎、与所有最新浏览器的独特高级集成、改进的工具栏以及大量其他改进和新功能&#xff0c;这一全新的更新&#xff0c;使得IDM下载器更加完美。值得一提的是&#xff0c;它可以借助油猴浏览器的脚本&…