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

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

🏷️系列专栏: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.hqwc.cn/news/492981.html

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

相关文章

【踩坑】修复报错 you should not try to import numpy from its source directory

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 报错如下&#xff1a; 修复方法一&#xff1a; pip install pyinstaller5.9 修复方法二&#xff1a; pip install numpy1.24.1

内部变形观测:监测仪器在工程中的应用

在工程领域&#xff0c;内部变形观测是确保建筑物安全稳定的关键环节。为了实现这一目标&#xff0c;我们需要借助一系列先进的仪器进行监测。本文将详细介绍在内部变形观测中常用的监测仪器。 垂直位移(沉降)观测在土石坝和混凝土坝中具有重要意义。对于土石坝&#xff0c;我们…

多态的讲解

多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同的状态。 举个栗子&#xff1a;比如买票这个行为&#xff0c;当普通人买票时&#xff0c;是全价买票&#xff1b;学生…

抖店是怎么运营做起来的?抖音小店每天都需要做什么?新手必看!

大家好&#xff0c;我是电商花花。 很多人疑惑开抖音小店之后&#xff0c;选好商品上架之后每天都需要做什么&#xff1f; 不少新手在开了抖音小店之后每天除了选品之后就不知道要做些什么了。 今天给大家分享一下我们每天做抖音小店的工作内容有哪些&#xff0c;如果你是新…

代码随想录算法训练营第二十一天| 530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先

文章目录 1.二叉搜索树的最小绝对差2.二叉搜索树中的众数3.二叉树的最近公共祖先 1.二叉搜索树的最小绝对差 因为二叉搜索树的中序遍历是有序的&#xff0c;所以在中序递归遍历的基础上&#xff0c;记录前一个节点的指针&#xff0c;递归的过程中用后一个节点减去前一个&#x…

企业数字化转型,如何选择适合的邮件系统?

随着数字经济的发展&#xff0c;数字办公已经成为企业未来发展的必经之路。而邮件系统作为企业内外沟通的重要办公工具&#xff0c;在企业数字化转型中发挥着重要作用。它能够帮助企业更便捷地跟踪管理业务&#xff0c;优化流程、提升工作效率和协同能力。但是&#xff0c;企业…

给自己留个备忘,blender是右手坐标系

所谓右手坐标系&#xff0c;就是三个轴的方向和右手三根手指的方向一致&#xff08;当然&#xff0c;有要求的&#xff0c;这个要求是大拇指指向x轴方向&#xff0c;食指指向y轴方向,中指指向z轴方向&#xff09;。 不过blender默认是z轴朝上的&#xff0c;如下图。 右手坐标系…

记阿里云mysql丢表丢数据的实践记录

第一时间挂工单&#xff0c;联系工程师指引&#xff0c;现在回过来想&#xff0c;第一时间要确认发生时间。 1.通过性能视图&#xff08;马后炮的总结&#xff0c;实际凭记忆恢复了三四次才找到数据&#xff09; 2.先恢复数据 通过Navicat工具&#xff0c;结构同步&#xff0…

linux操作系统期末练习题

背景&#xff1a; 一、远程登录 1&#xff0e;利用远程登录软件&#xff0c;以用户userManager(密码123456)&#xff0c;远程登录教师计算机&#xff08;考试现场给出IP地址&#xff09;&#xff0c;只有操作&#xff0c;没有命令。 2&#xff0e;以stu班级学生个人学号后3位…

[LWC] Components Communication

目录 Overview ​Summary Sample Code 1. Parent -> Child - Public Setter / Property / Function a. Public Property b. Public getters and setters c. Public Methods 2. Child -> Parent - Custom Event 3. Unrelated Components - LMS (Lightning Message…

Odoo系统安装部署并结合内网穿透实现固定域名访问本地ERP系统

文章目录 前言1. 下载安装Odoo&#xff1a;2. 实现公网访问Odoo本地系统&#xff1a;3. 固定域名访问Odoo本地系统 前言 Odoo是全球流行的开源企业管理套件&#xff0c;是一个一站式全功能ERP及电商平台。 开源性质&#xff1a;Odoo是一个开源的ERP软件&#xff0c;这意味着企…

mysql的增删改查(常用)

增(insert) 语法&#xff1a; insert into 表名&#xff08;字段&#xff09; values( 字段对应的值) 案例&#xff1a; 创建一个学生表 结构如下&#xff1a; create table student(id int ,name varchar(20),age int); 向表中插入2条数据 create table student(id int ,n…