Java8 Stream API 详解:流式编程进行数据处理

news2024/11/19 16:45:30

🏷️个人主页:牵着猫散步的鼠鼠 

🏷️系列专栏:Java全栈-专栏

🏷️个人学习笔记,若有缺误,欢迎评论区指正 

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站AI学习网站。  

目录

前言

Stream API的三个阶段

创建Stream流

Stream API中间操作

filter

map

flatMap

distinct

sorted

peek

limit 和 skip

Stream API终端操作

forEach

toArray

reduce

collect

count

anyMatch、allMatch 和 noneMatch

findAny 和 findFirst

min 和 max

注意事项

总结


前言

Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API。

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式

流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算!”

注意:

① Stream 自己不会存储元素。

② Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

③ Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream API的三个阶段

在Java中,Stream 是Java 8引入的一个新概念,用于处理集合(Collections)数据的一种抽象。Java的Stream API 提供了一种声明式的方式来操作数据集合,可以用更简洁、可读性更强的代码来进行集合的操作。

Java Stream API的操作可以分为三个阶段:

1. 创建流(Creation of Stream): 这个阶段涉及到从不同的数据源创建流,可以是集合、数组、I/O通道等。

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

2. 中间操作(Intermediate Operations): 这个阶段包括对流的转换操作,可以对流进行过滤、映射、排序等操作。这些操作并不会改变原始数据源,而是返回一个新的流。

Stream<Integer> filteredStream = stream.filter(x -> x > 2);

3. 终端操作(Terminal Operations): 这个阶段是对流进行最终操作,触发流的遍历,可以产生一个结果或者副作用。终端操作是流的最后一个操作,执行后流将不可再用。

long count = filteredStream.count();

这三个阶段的设计使得可以通过链式调用的方式组合多个操作,从而编写更为清晰和简洁的代码。这种方式也有助于提高代码的可读性和可维护性。

当然,这里只是对于Stream API三个阶段的概述,只是告诉大家,简单分为三个阶段,至于三个阶段里面有哪些主要的方法,我们在下文进行详细叙述,这里我们点到为止!现在,大家心里面就应该有这么一个蓝图,或者是基本框架,知道我们接下来将会沿着那个几个方向展开叙述!

创建Stream流

在Java中,你可以使用多种方式来创建Stream流。

从集合创建:

使用集合类的 stream() 或 parallelStream() 方法可以创建对应的流。例如:

List<String> list = Arrays.asList("apple", "banana", "orange");
Stream<String> streamFromList = list.stream();

从数组创建:

使用 Arrays.stream() 方法可以从数组中创建流:

String[] array = {"apple", "banana", "orange"};
Stream<String> streamFromArray = Arrays.stream(array);

通过Stream的静态方法创建:

Stream 类提供了静态方法 of(),可以传入一系列元素来创建流:

Stream<String> stream = Stream.of("apple", "banana", "orange");

使用Stream的generate和iterate方法:

Stream 类还提供了 generate 和 iterate 方法,用于生成无限流:

// 生成包含随机整数的无限流
Stream<Integer> infiniteStream = Stream.generate(() -> (int) (Math.random() * 100));

// 从指定的起始值开始,按照某个规则生成无限流
Stream<Integer> sequentialStream = Stream.iterate(1, n -> n + 1);

通过文件生成流:

java.nio.file.Files 类提供了静态方法 lines(),可以用来读取文件内容并生成流:

Path path = Paths.get("example.txt");
Stream<String> fileLines = Files.lines(path);

使用正则表达式生成流:

Pattern 类的 splitAsStream 方法可以根据正则表达式将字符串分割成流:

String text = "apple,orange,banana";
Stream<String> textStream = Pattern.compile(",").splitAsStream(text);

Stream API中间操作

Stream API 提供了许多中间操作,用于对流进行转换、筛选和处理。

filter

用于筛选元素,根据指定的条件保留符合条件的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> filteredStream = numbers.stream().filter(x -> x > 2);

map

对流中的每个元素应用指定的函数,并将结果映射为一个新的元素。

List<String> words = Arrays.asList("apple", "banana", "orange");
Stream<Integer> wordLengths = words.stream().map(String::length);

flatMap

将流中的每个元素都转换为一个流,然后将这些流连接起来成为一个流。

List<List<Integer>> numbers = Arrays.asList(
    Arrays.asList(1, 2),
    Arrays.asList(3, 4),
    Arrays.asList(5, 6)
);

Stream<Integer> flatStream = numbers.stream().flatMap(List::stream);

distinct

去除流中的重复元素。

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

sorted

对流中的元素进行排序。

List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);
Stream<Integer> sortedNumbers = numbers.stream().sorted();

peek

对流中的每个元素执行操作,主要用于调试和观察流中的元素。

List<String> words = Arrays.asList("apple", "banana", "orange");
Stream<String> peekStream = words.stream().peek(System.out::println);

limit 和 skip

limit 用于截断流,保留指定数量的元素,而 skip 则用于跳过指定数量的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> limitedStream = numbers.stream().limit(3);
Stream<Integer> skippedStream = numbers.stream().skip(2);

Stream API终端操作

Stream API 的终端操作用于触发对流的最终操作,产生结果或者引起副作用。

forEach

对流中的每个元素执行指定的操作。

List<String> words = Arrays.asList("apple", "banana", "orange");
words.stream().forEach(System.out::println);

toArray

将流中的元素转换为数组。

List<String> words = Arrays.asList("apple", "banana", "orange");
String[] wordArray = words.stream().toArray(String[]::new);

reduce

对流中的元素进行归约操作,可以用于求和、求最大值、最小值等。

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

collect

将流中的元素收集到一个集合中,例如 List、Set 或 Map。

List<String> words = Arrays.asList("apple", "banana", "orange");
List<String> collectedWords = words.stream().collect(Collectors.toList());

count

返回流中的元素数量。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
long count = numbers.stream().count();

anyMatch、allMatch 和 noneMatch

用于检查流中是否存在满足指定条件的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyGreaterThanThree = numbers.stream().anyMatch(x -> x > 3);
boolean allGreaterThanTwo = numbers.stream().allMatch(x -> x > 2);
boolean noneGreaterThanFive = numbers.stream().noneMatch(x -> x > 5);

findAny 和 findFirst

返回流中的任意一个元素或者第一个元素。

List<String> words = Arrays.asList("apple", "banana", "orange");
Optional<String> anyWord = words.stream().findAny();
Optional<String> firstWord = words.stream().findFirst();

min 和 max

返回流中的最小值或最大值。

List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);
Optional<Integer> minNumber = numbers.stream().min(Integer::compare);
Optional<Integer> maxNumber = numbers.stream().max(Integer::compare);

注意事项

使用Stream API时,有一些需要注意的重要事项,以确保正确、高效地利用这一功能:

只能使用一次: 一个 Stream 实例只能被消费(执行终端操作)一次。如果你尝试对已经使用过的流进行其他终端操作,会抛出 IllegalStateException 异常。如果需要再次操作,可以重新创建一个新的流。

List<String> words = Arrays.asList("apple", "banana", "orange");
Stream<String> wordStream = words.stream();

// 正确的做法
long count = wordStream.count();

// 错误的做法,会抛出IllegalStateException
long anotherCount = wordStream.count();

及早退出: 在处理大量数据时,及早退出可以提高性能。使用 anyMatch()、findFirst() 等终端操作时,一旦找到符合条件的元素,就会立即返回,不再继续处理后续元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyGreaterThanThree = numbers.stream().anyMatch(x -> {
    System.out.println("Checking: " + x);
    return x > 3;
});

并行流的谨慎使用: Stream API 提供了并行流的支持,可以通过 parallel() 方法将顺序流转换为并行流。但并不是所有的场景都适合使用并行流,因为在某些情况下,并行流可能会导致性能下降,甚至出现并发问题。在并行流的使用上需要注意线程安全等问题。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
long count = numbers.parallelStream().filter(x -> x > 2).count();

使用适当的数据结构: 在创建流时,选择适当的数据结构能够影响流操作的性能。例如,ArrayList 在顺序访问时性能较好,而 LinkedList 在随机访问时性能较好。

总结

总体而言,了解Stream API的使用原则,结合具体的业务场景和性能需求,能够更好地利用Stream API完成任务。注意流的延迟计算特性,避免副作用,可以使代码更加清晰、可读,并提高代码的可维护性。

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

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

相关文章

xss靶场实战(xss-labs-master靶场)

xss-labs-master靶场链接&#xff1a;https://pan.baidu.com/s/1X_uZLF3CWw2Cmt3UnZ1bTw?pwdgk9c 提取码&#xff1a;gk9c xss-labs level 1 修改 url 地址中的name<script>alert(1)</script>&#xff0c;便可以通关 level 2 在搜索框中输入的 JS 代码无法执行 …

vDPA测试环境搭建

要求&#xff1a; 运行 Linux 发行版的计算机。本指南使用 CentOS 9-stream&#xff0c;但对于其他 Linux 发行版&#xff0c;特别是对于 Red Hat Enterprise Linux 7&#xff0c;命令不应有重大变化。 具有 sudo 权限的用户 ~ 主目录中有 25 GB 的可用空间 至少 8GB 内存 …

完美解决ubuntu+windows双系统下时间不正确问题

在同一台电脑上安装ubuntuwindows双系统时&#xff0c;会出现某个系统的时间不正确的问题&#xff0c;而由于windows同步时间实在是太慢了&#xff0c;如果不去解决&#xff0c;windows上的时间大概率一直都是不对的。 原因分析 windows采用LocalTime机制设置时间&#xff0c…

车载电子电器架构 —— OEM基础技术概念开发流程

车载电子电器架构 —— 基础技术概念开发 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明…

Sora—openai最新大模型文字生成视频

这里没办法发视频&#xff0c;发几个图片感受感受吧 OpenAI发布了Sora&#xff0c;一种文字生成视频的技术&#xff0c;从演示看&#xff0c;效果还是相当不错的。 Sora的强大之处在于其能够根据文本描述&#xff0c;生成长达 60秒的视频&#xff0c;其中包含精细复杂的场景…

26.HarmonyOS App(JAVA)列表对话框

列表对话框的单选模式&#xff1a; //单选模式 // listDialog.setSingleSelectItems(new String[]{"第1个选项","第2个选项"},1);//单选 // listDialog.setOnSingleSelectListener(new IDialog.ClickedListener() { // Override …

3_怎么看原理图之协议类接口之I2C笔记

I2C只连接I2CSCL与I2CSDA两根线&#xff0c;即2线制异步串行总线。 I2CSCL与I2CSDA两根线需要上拉电阻&#xff0c;目的是让电平有确定的状态。 发完8bit数据后&#xff0c;第9个电平拉低SDA为低电平。 比如传一个数据A0x410100 0001 IIC总线有多个从机设备的通信&#xff0c…

探索水下低光照图像检测性能,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建海底生物检测识别分析系统

海底这类特殊数据场景下的检测模型开发相对来说比较少&#xff0c;在前面的博文中也有一些涉及&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a; 《尝试探索水下目标检测&#xff0c;基于yolov5轻量级系列模型n/s/m开发构建海底生物检测系统》 《基于YOLOv5C3CBAMCBA…

便携式航空电源-飞机启动电源的创新设计

在航空航天领域&#xff0c;电力供应是至关重要的。无论是飞机、直升机还是无人机&#xff0c;都需要稳定、可靠的电力支持以确保飞行的安全和效率。便携式航空电源这种飞机地面方便携带的启动电源应运而生&#xff0c;为航空航天领域带来了新的动力。 便携式航空电源是一种专…

GO-ICP的使用(一)

一、代码下载以、修改以及使用 下载&#xff1a; 链接&#xff1a;yangjiaolong/Go-ICP: Implementation of the Go-ICP algorithm for globally optimal 3D pointset registration (github.com) 解压之后 &#xff1a; 首先visual studio项目&#xff0c;配置好PCL环境&…

软件应用场景,物流货运配货单打印模板软件单据打印查询管理系统软件教程

软件应用场景&#xff0c;物流货运配货单打印模板软件单据打印查询管理系统软件教程 一、前言 以下软件以 佳易王物流快运单打印查询管理系统软件V17.1 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、打印模式可以分为 直打模式和套打模式 直打模…

消息中间件之RocketMQ源码分析(十六)

Broker读写分离机制 在RocketMQ中,有两处地方使用了"读写分离"机制 Broker Master-Slave读写分离:写消息到Master Broker,从Slave Broker读取消息。Broker配置为Slave Broker读取消息。 Broker配置为slaveReadEnableTrue(默认False)&#xff0c;消息占用内存百分比配…

力扣随笔之寻找重复数(中等287)

思路1&#xff1a;暴力解法&#xff0c;根据要求不修改数组且只用常量级O(1)的额外空间&#xff0c;我们写两层嵌套循环&#xff0c;寻找重复的数;可以解决部分问题&#xff0c;但会超出时间限制无论Java还是C; Java实现&#xff1a; class Solution {public int findDuplicat…

WSL里的Ubuntu 登录密码忘了怎么更改

环境&#xff1a; Win10 专业版 WSL2 如何 Ubuntu22.04 问题描述&#xff1a; WSL里的Ubuntu 登录密码忘了怎么更改 解决方案&#xff1a; 在WSL中的Ubuntu系统中&#xff0c;忘记了密码&#xff0c;可以通过以下步骤重置密码&#xff1a; 1.打开命令提示符或PowerShel…

[HTML]Web前端开发技术29(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 上一节的课后练习

Stable Diffusion 3重磅发布

刚不久&#xff0c;Stability AI发布了Stable Diffusion 3.0&#xff0c;这一版本采用了与备受瞩目的爆火Sora相同的DiT架构。通过这一更新&#xff0c;画面质量、文字渲染以及对复杂对象的理解能力都得到了显著提升。由于这些改进&#xff0c;先前的技术Midjourney和DALL-E 3在…

【Vue3】‘vite‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

问题 今天拿到别人项目的时候&#xff0c;我平时比较习惯用pnpm&#xff0c;我就使用pnpm i先下载依赖包&#xff0c;下载完成后&#xff0c;启动项目&#xff0c;就开始报以下错误&#xff01; 但是当我执行pnpm i的时候&#xff0c;vite不应该就已经被我下载下来了吗 研究了…

vivo 基于 StarRocks 构建实时大数据分析平台,为业务搭建数据桥梁

在大数据时代&#xff0c;数据分析和处理能力对于企业的决策和发展至关重要。 vivo 作为一家全球移动互联网智能终端公司&#xff0c;需要基于移动终端的制造、物流、销售等各个方面的数据进行分析以满足业务决策。 而随着公司数字化服务的演进&#xff0c;业务诉求和技术架构有…

解密高并发系统设计:聊聊负载均衡算法

引言 随着公司业务的飞速发展&#xff0c;以及业务的多样性&#xff0c;用户数会迅猛增长&#xff0c;系统的流量会越来越大。因此&#xff0c;大规模的并发用户访问会对系统的处理能力造成巨大的压力&#xff0c;系统必须要有足够强的处理能力才能应对。 这篇文章就来介绍一…

VMware使用虚拟机,开启时报错:无法连接虚拟设备 0:0,因为主机上没有相应的设备。——解决方法

检查虚拟机配置文件并确保物理设备已正确连接。 操作&#xff1a; 选中虚拟机&#xff0c;打开设置&#xff0c;点击CD/DVD。在连接处选择使用ISO镜像文件