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

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 可以显著提升代码的可读性和稳定性。

黑马程序员免费预约咨询

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

先进制造aps专题十一 国内软件/erp行业的现状及对aps行业的启示

看到一个帖子 中国软件行业几乎全军覆没 OSC开源社区 2024-06-03 15:58 广东 刚刚网上冲浪刷到的 网友锐评&#xff1a;都是客户关系型公司。 知名大 V 「Fenng」评论称&#xff1a; 这里所谓的软件行业公司如果立刻倒闭&#xff0c;才能够利好中国整个行业软件生态。有个网…

【云原生】Kubernetes----RBAC用户资源权限

目录 引言 一、Kubernetes安全机制概述 二、认证机制 &#xff08;一&#xff09;认证方式 1.HTTPS证书认证 1.1 证书颁发 1.2 config文件 1.3 认证类型 1.4 Service Account 1.4.1 作用 1.4.2 包含内容 1.4.3 与Secret的关系 2.Bearer Tokens 3.基本认证 三、鉴…

【Java数据结构】二叉树详解(四)

&#x1f512;文章目录&#xff1a; 1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; 2.给定一个二叉树, 找到该树中两个指定节点的最近公共祖先 2.1第一种思路 2.2第二种思路 3.根据一棵树的前序遍历与中序遍历构造二叉树 4.根据一棵树的中序…

短视频外卖平台区域代理怎么拿?两种方法!

抖音外卖平台区域代理怎么拿&#xff1f;市面上只有两种途径可走。没有其他任何方法。 一是拿抖音官方区域服务商身份&#xff0c;第一个要求是保证金50万&#xff0c;公司必须还要有20个人以上的社保证明。同时还要提供企业半年的银行资金流水。如果小型公司基本是不用考虑的…

pcb实验六-元件设计

目录 一&#xff0c;绘制28管脚PLCC封装ATF750C-10JC元件 二&#xff0c;绘制变压器原理图符号&#xff0c;并生成各种库文件输出报表 1&#xff0c;绘制变压器原理图 2&#xff0c;添加封装 3&#xff0c;输出报表文件 三&#xff0c;绘制音乐集成芯片及LCD元件 1&…

隐马尔可夫模型

目录 1. 通信系统 2. 各种“马尔可夫”们 2.1 马尔可夫假设 2.2 马尔可夫链 2.3 隐马尔可夫模型 2.3.1 将隐马尔可夫模型应用于解码问题 2.3.2 如何训练隐马尔可夫模型 2.3.2.1 有监督的训练 2.3.2.2 无监督的训练 1. 通信系统 通信的本质就是一个【编码传输解码】的…

【C++】STL:栈和队列模拟实现

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

【设计模式深度剖析】【2】【行为型】【命令模式】| 以打开文件按钮、宏命令、图形移动与撤销为例加深理解

&#x1f448;️上一篇:模板方法模式 | 下一篇:职责链模式&#x1f449;️ 设计模式-专栏&#x1f448;️ 文章目录 命令模式定义英文原话直译如何理解呢&#xff1f; 四个角色1. Command&#xff08;命令接口&#xff09;2. ConcreteCommand&#xff08;具体命令类&…

linux进程间通讯指南-打通IPC大门,高效沟通无阻

在现代操作系统中&#xff0c;进程就像独立的个体&#xff0c;有时需要相互合作、数据共享&#xff0c;这就要求进程间能够高效通信。本文将为你揭开Linux进程间通信(IPC)的神秘面纱&#xff0c;探讨各种IPC工具的运作原理&#xff0c;同步机制的重要性&#xff0c;以及如何规避…

Ubuntu安装cuda

文章目录 前言一、安装NVIDIA驱动1.1 过程中的问题1.2 解决方法1.3 重启后出现 perform MOK management 二、安装Cuda2.1 检查是否安装显卡驱动2.2 安装Cuda2.3 验证CUDA是否安装成功 三、配置环境变量---未完2.4 图片居中加调整大学 总结 #pic_center 前言 只是为方便学习&…

淘宝扭蛋机源码解析:功能实现与技术细节

随着在线购物和娱乐的融合&#xff0c;淘宝扭蛋机作为一种创新的购物娱乐方式&#xff0c;受到了广大用户的喜爱。本文将深入解析淘宝扭蛋机的源码&#xff0c;探讨其功能实现与技术细节&#xff0c;以期为开发者们提供一些有价值的参考。 一、功能实现 1.用户登录与注册 淘宝…

win11通过网线分享网络到Ubuntu工控机

1.条件&#xff1a;一个能无线联网的win11&#xff0c;一根网线&#xff0c;一台Ubuntu工控机&#xff0c;并且使用网线连接两者 2.在win11电脑上 2.1 打开控制面板的网络和Internet 2.2 进入网络和共享中心&#xff0c;在左侧进入 更改适配器设置 2.3 在WLAN上右键&#xff0…

R语言数据探索和分析21-中国GDP及其影响因素多元线性回归分析

一、研究背景和意义 GDP 是宏观经济中最受关注的经济统计数字&#xff0c;目前我国国内生产总值年均增长率均明显高于同期美、日等发达经济体和巴 西、俄罗斯、南非、印度等其他金砖国家&#xff0c;成为世界经济增长的主力军&#xff0c;GDP 的增长对一个国家有着十分重要的意…

TSINGSEE青犀视频:城市道路积水智能监管,智慧城市的守护者

随着城市化进程的加快&#xff0c;城市道路网络日益复杂&#xff0c;尤其在夏季&#xff0c;由于暴雨频发&#xff0c;道路积水问题成为影响城市交通和市民生活的重要因素之一。传统的道路积水监测方式往往依赖于人工巡逻和简单的监控设备&#xff0c;这些方法存在效率低下、响…

软信天成:告别数据脏乱差!企业数据清洗实战方案分享

低质量数据普遍存在。据统计&#xff0c;数据质量问题每年给企业造成高达3.1万亿美元的损失。为了防范这种损失&#xff0c;越来越多的企业采用数据清洗来清洗数据&#xff0c;提高数据质量。 数据清洗&#xff0c;顾名思义是将数据上“脏”的部分清洗掉&#xff0c;让数据变得…

读《淘宝技术这10年》:从进化中感受技术的美与挑战

本文作者:小米,一个热爱技术分享的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 大家好,我是小米,一个29岁的程序员,喜欢分享技术干货。今天,我想和大家聊一聊我最近读的一本书——《淘宝技术这10年》。这本书让我深刻领悟…

JetBrains PhpStorm 激活码限时特惠 7.1 折快抢!

各位程序员&#xff0c;每天敲代码真的需要一款好用的 IDE&#xff0c;大名鼎鼎的 JetBrains 值得信赖&#xff01;PHP 开发看过来&#xff0c;PhpStorm 个人版首年订阅 618 限时特惠 7.1 折&#xff0c;有需要的朋友一定不要错过&#xff01; PhpStorm 汇集了众多效率功能和集…

【微信小程序】网络请求

出于安全性方面的考虑&#xff0c;小程序官方对数据接口的请求做出了如下两个限制&#xff1a; 只能请求HTTPS类型的接口必须将接口的域名添加到信任列表中 登录微信小程序管理后台->开发->开发设置->服务器域名->修改request合法域名。 注意事项&#xff1a; 域…

视频汇聚EasyCVR安防监控系统GA/T 1400协议视图库对接:技术实现与应用

随着信息技术的不断发展&#xff0c;各类协议标准在各个领域得到了广泛应用。GA/T1400协议作为公安视频监控系统中的一种重要标准&#xff0c;对于提升公安工作的信息化水平、加强社会治安防控具有重要意义。本文将重点探讨GA/T1400协议视图库对接的技术实现及应用价值。 一、…

领菲linfeeLNF96E多功能电力仪表智能数码液晶显示三相电压电流表

品牌 LINFEE 型号 LNF96E 货号 LNF96E 产地 中国大陆 省份 江苏省 地市 无锡市 装修及施工内容 安装工程 电源电路 交流电表 电表类型 多功能电度表 颜色分类 LNF96E-C,LNF96E-CM,LNF96E-CJ,LNF96E-CK,LNF96E-CJK,LNF96E-CMJK 多功能电力仪表,LNF96E三相多…