02-JDK新特性-Stream流

Stream流

什么是Stream流

Stream流是Java 8中的一个新特性,它提供了一种处理集合和数组的方式。Stream流可以让我们以一种更加简洁、高效、可读性更强的方式来处理数据。

Stream流可以用于过滤、映射、排序、聚合等操作,它可以让我们避免使用循环和条件语句来处理数据,从而让代码更加简洁易懂。

Stream流的操作可以分为中间操作和终止操作两种类型,中间操作返回的是一个新的Stream流,终止操作返回的是一个非Stream类型的结果。

Stream流的处理是惰性求值的,只有在执行终止操作时才会开始处理数据。

流(Stream)是一种基于支持一次性处理数据的数据源的元素序列,流只能使用一次。

流的设计初衷是为了支持函数式编程,它的目的是将数据处理和数据存储分离开来,使得数据处理更加灵活和高效。因此,流的元素只是在流中传递的临时数据,它们并不是永久存储在内存中的数据。

当流的元素被消费后,它们就会被释放,不能再次使用.。如果需要对同一个数据集进行多次不同的操作,可以使用流的中间操作方法来构建多个流管道,每个流管道都可以对流进行不同的操作,并返回一个新的流。这样就可以对同一个数据集进行多次操作,而不需要重新获取数据集。

流的分类

顺序流

顺序流是一种单线程的流,它按照数据流的顺序依次处理每个元素,每个元素的处理都必须等待上一个元素的处理完成才能开始

并行流

并行流是一种多线程的流,它可以将数据分成多个部分并行处理,每个部分都可以在不同的线程中处理,从而提高处理效率。

使用顺序流可以保证数据处理的顺序和一致性,适用于处理数据量较小的情况。而使用并行流可以提高数据处理的速度,适用于处理数据量较大、处理时间较长的情况。

但是并行流也有一些缺点,比如线程之间的通信和同步会带来额外的开销,而且并行流可能会影响数据的顺序和一致性。因此在使用并行流时需要注意线程安全和数据一致性等问题

区别

顺序流和并行流的区别在于它们的处理方式不同,顺序流是单线程的,而并行流是多线程的。使用的方法也有一些区别,例如:

  • 获取顺序流:可以使用集合类的stream()方法、Arrays类的stream()方法、Stream类的of()方法、Stream类的iterate()方法、Stream类的generate()方法、Files类的lines()方法等来获取顺序流。
  • 获取并行流:可以使用集合类的parallelStream()方法、Stream类的of()方法的parallel()方法、Stream类的iterate()方法的parallel()方法、Stream类的generate()方法的parallel()方法等来获取并行流。

除此之外,顺序流和并行流的使用方法基本相同,例如可以使用map()、filter()、reduce()等方法对流进行操作。但需要注意的是,在使用并行流时需要考虑线程安全和数据一致性等问题。

Stream流的使用

按照的处理过程可以分为

  1. 生成流

    通过数据源(集合、数组等)生成流,例如:list.stream()
  2. 中间操作

    一个流后面可以跟随零个或多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流交给下一个操作使用.例如:filter()
  3. 终结操作

    一个流只能有一个终结操作,当这个操作执行后,流就被使用完了,无法在继续操作。所以着必定是流的最后一个操作。例如:forEach()

生成流的方式

  1. 通过集合获取流
package demo1;import java.util.*;
import java.util.stream.Stream;/*** 生成流的方式:* 通过集合获取流:可以使用集合类中的stream()方法或parallelStream()方法来获取流** @author Anna.* @date 2024/4/3 16:18*/
public class StreamDemo01 {public static void main(String[] args) {System.out.println("=======List========");System.out.println("=======顺序流========");List<String> list = Arrays.asList("林青霞", "张曼玉", "王祖贤", "柳岩", "张敏", "张无忌");// 通过集合中stream()获取顺序流Stream<String> stream = list.stream();// 循环输出stream.forEach(System.out::println);System.out.println("=======并行流========");// 通过集合中stream()获取并行流Stream<String> parallelStream = list.parallelStream();parallelStream.forEach(s -> System.out.printf("%s 输出了:%s%n", Thread.currentThread().getName(), s));System.out.println("=======Set========");Set<String> set = new HashSet<String>(list);// 通过stream()获取顺序流Stream<String> streamSet = set.stream();// 循环输出streamSet.forEach(System.out::println);// 并行流演示(后续单独说)System.out.println("=======Map========");// Map中没有提供直接转换成Stream流的相应的方法,但是可以通过间接的方式获取Map<String, String> map = new HashMap<String, String>();map.put("name", "林青霞");map.put("age", "30");// 获取Map中keySet对应的Stream流Stream<String> stream1 = map.keySet().stream();stream1.forEach(System.out::println);// 获取Map中values对应的Stream流Stream<String> stream2 = map.values().stream();stream2.forEach(System.out::println);// 获取Map中entrySet对应的Stream流Stream<Map.Entry<String, String>> stream3 = map.entrySet().stream();stream3.forEach(s -> {System.out.printf("key=%s,value=%s%n", s.getKey(), s.getValue());});}
}
  1. 通过Arrays数组工具类中stream()方法获取流
package demo1;import java.util.Arrays;
import java.util.stream.Stream;/*** 生成流的方式:* 通过Arrays数组工具类中stream()方法获取流*  Arrays  没有提供并行流的原因是因为数组在内存中是连续存储的,不能像集合那样方便地分割成多个部分进行并行处理。  如果要对数组进行并行处理,需要将其转换为流或使用并发编程技术手动分割和处理数组的不同部分。因此,并行流更多地是针对集合类数据结构而设计的。* @author Anna.* @date 2024/4/3 16:18*/
public class StreamDemo02 {public static void main(String[] args) {String[] arr = {"林青霞", "张曼玉"};Stream<String> stream = Arrays.stream(arr);// 循环输出stream.forEach(System.out::println);}
}

注意:

Arrays 没有提供并行流的原因是因为数组在内存中是连续存储的,不能像集合那样方便地分割成多个部分进行并行处理。

如果要对数组进行并行处理,需要将其转换为流或使用并发编程技术手动分割和处理数组的不同部分。因此,并行流更多地是针对集合类数据结构而设计的。

  1. 通过 Stream.of()方法获取流
package demo1;import java.util.stream.Stream;/*** 生成流的方式:* 通过 Stream.of()方法获取流** @author Anna.* @date 2024/4/3 16:18*/
public class StreamDemo03 {public static void main(String[] args) {String[] arr = {"林青霞", "张曼玉"};Stream<String> stream = Stream.of(arr);// 循环输出stream.forEach(System.out::println);}
}
  1. 通过Stream.iterate()方法获取流
package demo1;import java.util.stream.Stream;/*** 生成流的方式:* 通过Stream.iterate()方法获取流:可以使用 Stream 类中的iterate()方法来获取流** @author Anna.* @date 2024/4/3 16:18*/
public class StreamDemo04 {public static void main(String[] args) {Stream<Integer> stream = Stream.iterate(1, (x) -> x + 100).limit(3);stream.forEach(System.out::println);}
}

执行结果

在这里插入图片描述

  1. 通过Stream.generate()方法获取流
package demo1;import java.util.stream.Stream;/*** 生成流的方式:* 通过Stream.generate()方法获取流:可以使用 Stream 类中的generate()方法来获取流** @author Anna.* @date 2024/4/3 16:18*/
public class StreamDemo05 {public static void main(String[] args) {Stream<String> stream = Stream.generate(() -> new String("a123")).limit(3);stream.forEach(System.out::println);}
}

执行结果

在这里插入图片描述

  1. 通过Files.lines()方法获取流

GenStream.txt

张三,30
李四,20
王五,40
package demo1;import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;/*** 生成流的方式:* 通过Files.lines()方法获取流:可以使用Files类中的lines()方法来获取流。** @author Anna.* @date 2024/4/3 16:18*/
public class StreamDemo06 {public static void main(String[] args) throws IOException {new StreamDemo06().genStreamByFile();}public void genStreamByFile() throws IOException {Stream<String> lines = Files.lines(Paths.get("D:/WordkSpaces/JavaWorkSpaces/IdeaWorkSpaces/StudyWorkSpaces/JavaStudyWorkSpaces/02-new-feature-stream/src/main/resources/GenStream.txt"));lines.forEach(System.out::println);}
}

执行结果

在这里插入图片描述

中间操作

常用中间操作如下:

分类方法名作用
筛选与切片
-filter(Predicate<? super T> predicate)保留满足给定条件的元素
-distinct()返回由该流的不同元素(根据Object.equals(Object))组成的流
-limit(long maxSize)返回一个新流,其元素是该流的前n个元素
-skip(long n)跳过前n个元素
映射
-map(Function<? super T,? extends R> mapper)将每个元素应用到一个函数上,并返回结果的新流
-flatMap(Function<? super T,? extends Stream<? extends R>> mapper)将每个元素应用到一个函数上,该函数产生一个流,然后将所有产生的流连接成一个流
排序
-sorted()返回由该流的元素组成的流,根据元素的自然顺序排序(即按照字母顺序)
-sorted(Comparator<? super T> comparator)返回由该流的元素组成的流,根据提供的Comparator进行排序
有状态操作
-distinct()虽然不是典型的有状态操作,但在某些实现中,它可能需要跟踪遇到的元素以提供不同的结果
-sorted()这是一个有状态操作,因为它需要维护一个内部状态来跟踪排序顺序

注意:

不是所有的中间操作都是有状态的。有状态的操作是那些需要访问多个输入元素才能产生输出元素的操作,比如sorted(),它需要在整个流上操作以产生排序后的结果。

此外,还有一些组合器操作,如peek(Consumer<? super T> action),它主要用于调试目的,允许在流的处理过程中执行某些操作,但并不改变流的内容。

终结操作

常用终结操作如下:

方法名作用
forEach(Consumer<? super T> action)对流中的每个元素执行给定的操作。例如,可以用于打印流中的每个元素或执行其他副作用。
collect(Collector<? super T,A,R> collector)将流中的元素累积到一个汇总结果中,如List、Set或自定义类型。
reduce(T identity, BinaryOperator accumulator)将流中的元素使用提供的累积器函数组合起来,以产生单个输出值。
reduce(BinaryOperator accumulator)这是上一个reduce方法的简化版本,它假定流不为空,并且没有提供初始值。
anyMatch(Predicate<? super T> predicate)检查流中是否至少有一个元素满足给定的条件。
allMatch(Predicate<? super T> predicate)检查流中的所有元素是否都满足给定的条件。
noneMatch(Predicate<? super T> predicate)检查流中是否没有任何元素满足给定的条件。
findAny()返回流中的某个元素。此操作对于并行流可能返回流中的任何元素。
findFirst()返回流中的第一个元素。对于有序流,这将是第一个元素;对于无序流,这将是遇到的某个元素。
count()返回流中的元素数量。
max(Comparator<? super T> comparator)返回流中的最大元素,根据提供的比较器进行排序。
min(Comparator<? super T> comparator)返回流中的最小元素,根据提供的比较器进行排序。
toArray()将流中的元素收集到一个新数组中。

注意:

一旦执行了终结操作,流就会被消费掉,并且不能再次使用。如果你需要再次处理相同的数据,你需要重新创建流。同时,终结操作会触发流的中间操作链的执行,从而生成最终的结果。

案例

如图使用Stream对一个集合List,生成流后,首先筛选以张开头的姓名,然后筛选长度为3的姓名,最后输出结果

在这里插入图片描述

package demo2;import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;/*** 使用Stream对一个集合List,生成流后,首先筛选以张开头的姓名,然后筛选长度为3的姓名,最后输出结果*   List<String> list = Arrays.asList("林青霞", "张曼玉", "王祖贤", "柳岩", "张敏", "张无忌");** @author Anna.* @date 2024/4/3 20:40*/
public class StreamDemo {public static void main(String[] args) {// 创建集合List<String> list = Arrays.asList("林青霞", "张曼玉", "王祖贤", "柳岩", "张敏", "张无忌");// 获取流Stream<String> stream = list.stream();// 执行操作,输出结果stream.filter(s -> s.startsWith("张"))   // 筛选以张开头的姓名.filter(s -> s.length() == 3)   // 筛选长度为3的姓名.forEach(System.out::println);  // 输出结果;}
}

执行结果
在这里插入图片描述

Stream的特点

  1. stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果;
  2. stream对于值传递的集合不改变数据源,如果是对象则 引用传递则会改变数据源
  3. stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行
  4. stream不可复用,对一个已经进行过终端操作的流再次调用,会抛出异常。

案例

package demo3;import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;/*** 验证* 1 stream对于值传递的集合不改变数据源,如果是对象则 引用传递则会改变数据源* 2 只有调用终端操作时,中间操作才会执行* 3 stream不可复用** @author Anna.* @date 2024/4/3 20:47*/
public class StreamDemo {/*** 定义一个内部内*/static class UserDo {private String name;private Integer age;public UserDo(String name, Integer age) {this.name = name;this.age = age;}public void setName(String name) {this.name = name;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "UserDo{" +"name='" + name + '\'' +", age=" + age +'}';}}public static void main(String[] args) {System.out.println("===============验证stream对于值传递的集合不改变数据源================");// 创建一个List集合List<Integer> list = Arrays.asList(1, 2, 3);// 获取流修改数据list.stream().map(s -> 20).forEach((s) -> System.out.printf("输出Straem处理后结果:%s%n", s));// 输出源数据list.forEach((s) -> {System.out.printf("输出源数据:%s%n", s);});System.out.println("===============验证stream对于对象引用传递则会改变数据源================");// 创建一个List集合List<UserDo> userDos = Arrays.asList(new UserDo("张三", 20), new UserDo("李四", 20));// 获取流Stream<UserDo> stream = userDos.stream();// 通过流将集合中所有所有UserDo属性age设置为30,并输出结果stream.map(s -> {    // 属性age设置为30s.setAge(30);return s;}).forEach((s) -> { // 输出结果System.out.printf("输出Straem处理后结果:%s%n", s);});// 输出源数据userDos.forEach((s) -> {System.out.printf("输出源数据:%s%n", s);});// 验证stream终结后是否可以复用// 报错 提示 Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
//        stream.map(s ->{    // 属性age设置为30
//            s.setAge(30);
//            return s;
//        }).forEach((s) ->{System.out.printf("输出Straem处理后结果:%s%n");});    // 输出结果System.out.println("===============验证只有调用终端操作时,中间操作才会执行================");// 验证只有调用终端操作时,中间操作才会执行// 重新获取流userDos.stream().peek(s -> System.out.println("===执行了===="));}
}

执行结果

在这里插入图片描述

gitee源码

git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

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

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

相关文章

实验2:CLI的使用与IOS基本命令

1、实验目的 通过本实验可以掌握&#xff1a; CLI的各种工作模式个CLI各种编辑命令“?” 和【Tab】键使用方法IOS基本命令网络设备访问限制查看设备的相关信息 2、实验拓扑 CLI的使用与IOS基本命令使用拓扑如下图所示。 3、实验步骤 &#xff08;1&#xff09;CLI模式的切…

openwrt开发包含路由器基本功能的web问题记录

1.这里的扫描怎么实现的先找一些luci代码&#xff0c;在openwrt21版本后&#xff0c;luci用js替换了lua写后台&#xff0c;先找一些代码路径 在openrwt15这部分代码是在这个目录下 feeds/luci/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm 里面包含…

自然语言处理NLP概述

大家好&#xff0c;自然语言处理(NLP)是计算机科学领域与人工智能领域中的一个重要方向&#xff0c;其研究能实现人与 计算机之间用自然语言进行有效通信的各种理论和方法。本文将从自然语言处理的本质、原理和应用三个方面&#xff0c;对其进行概述。 一、NLP的本质 NLP是一…

[HackMyVM]靶场Boxing

难度:Medium kali:192.168.56.104 靶机:192.168.56.143 端口扫描 ┌──(root㉿kali2)-[~/Desktop] └─# nmap 192.168.56.143 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-03 19:25 CST Nmap scan report for staging-env.boxing.hmv (192.168.56.143) Host …

v-text 和v-html

接下来&#xff0c;我讲介绍一下v-text和v-html的使用方式以及它们之间的区别。 使用方法 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-widt…

计算机网络_工具

从你的电脑到指定ip网站&#xff0c;用时3ms ttl TTL Time To Live 数据包存活时间 指一个数据包在经过一个路由器时&#xff0c;可传递的最长距离&#xff08;跃点数&#xff09;。每当数据包经过一个路由器时&#xff0c;其存活次数就会被减一 256 - 249 7&…

软件设计师28--SQL语言

软件设计师28--SQL语言 考点1&#xff1a;普通查询SQL语言SQL语言 - 查询例题&#xff1a; 考点2&#xff1a;分组查询SQL语言 - 查询例题&#xff1a; 考点3&#xff1a;权限控制SQL语言例题&#xff1a; 考点1&#xff1a;普通查询 SQL语言 SQL语言 - 查询 例题&#xff1a;…

远程登录服务器(ubuntu20.04)在自己账号下的虚拟环境(python3.6)安装Jupyter并连接pycharm使用

参考&#xff1a;Jupyter notebook/lab安装及远程访问 1、安装jupyter pip install notebook遇到的问题&#xff1a; &#xff08;1&#xff09;运行这个指令之前尝试了好多方法都安不上 此前还尝试了更新pip之类的&#xff0c;大家安不上也可以先更新pip试试。 &#xff0…

职场聚餐:搭建沟通桥梁,促进团队凝聚力

在职场中&#xff0c;聚餐作为一种非正式的社交活动&#xff0c;不仅能够增进同事间的了解&#xff0c;还有助于提升团队凝聚力。本文将探讨职场聚餐的重要性以及如何组织一场成功的职场聚餐。 一、职场聚餐的重要性 1. 搭建沟通桥梁&#xff1a;职场聚餐为员工提供了一个轻松愉…

电商好评语整理与优化:让繁琐工作变得轻松高效

在电子商务领域&#xff0c;客户的好评是店铺信誉和产品质量的重要体现。然而&#xff0c;整理和优化这些好评语却是一项既繁琐又需要细致耐心的工作。本文将探讨如何高效地进行电商好评语的筛选、分类和优化&#xff0c;让这一工作变得更加轻松和高效。 一、明确整理目的 在开…

webapi 允许跨域

1.在Nuget安装webapi.cors 添加完会有这个包 然后在项目App_Start 目录下的WebApiConfig.cs里面添加 // Web API 配置和服务// 添加跨域设置config.EnableCors(new EnableCorsAttribute("*", "*", "*"));

[C++ ]21:哈希+海量数据处理

[C ]21:哈希海量数据处理 一.哈希&#xff1a;1.位图&#xff1a;1.题目一&#xff1a;方法一&#xff1a;方法二&#xff1a; 2.题目二&#xff1a;方法一&#xff1a;补充&#xff1a; 3.题目三&#xff1a;方法一&#xff1a;双位图 4.题目四&#xff1a; 二.布隆过滤器&…

k8s的pod访问service的方式

背景 在k8s中容器访问某个service服务时有两种方式&#xff0c;一种是把每个要访问的service的ip注入到客户端pod的环境变量中&#xff0c;另一种是客户端pod先通过DNS服务器查找对应service的ip地址&#xff0c;然后在通过这个service ip地址访问对应的service服务 pod客户端…

如何使用Java语言发票查验接口实现发票真伪查验、票据ocr

随着时代潮流的发展&#xff0c;企业也在寻找更加便捷、高效的办公模式&#xff0c;尤其是针对财务工作人员而言&#xff0c;繁琐的发票录入、查验工作占据了财务人员的大部分时间。对此&#xff0c;翔云提供了发票识别接口、发票查验接口&#xff0c;那么企业应当如何将这些接…

数据结构算法题(力扣)——链表

以下题目建议大家先自己动手练习&#xff0c;再看题解代码。这里只提供一种做法&#xff0c;可能不是最优解。 1. 移除链表元素&#xff08;OJ链接&#xff09; 题目描述&#xff1a;给一个链表的头节点 head 和一个整数 val &#xff0c;删除链表中所有满足值等于 val 的节点…

【 书生·浦语大模型实战营】学习笔记(一):全链路开源体系介绍

&#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料&#xff0c;配有全面而有深度的专栏内容&#xff0c;包括不限于 前沿论文解读、…

linux 回收站机制(笔记)

Linux下回收站机制https://mp.weixin.qq.com/s/H5Y8VRcaOhFZFXzR8yQ7yg 功能 &#xff1a;设立回收站&#xff0c;并且可定时清空回收站。 一、建议将alias rm 改成别的。 比如alias rmm &#xff0c;同时修改rm -rf ~/.trash/* 改成 rmm -rf ~/.trash/* 不然影响rm 的正常使…

js 基础知识 forEach 和 map 的区别,及 map 不加 return 返回什么

问题一&#xff1a;forEach 和 map 之间的区别&#xff1a; 1、forEach 不返回新数组&#xff0c;map 返回新数组&#xff0c;其中包含回调函数的返回值。 2、用途&#xff1a;如果只想要遍历数组并对每个元素执行某些操作而不产生新数组&#xff0c;那么应该使用 forEach&am…

从零开始学RSA加密解密过程

因为文字太过晦涩难懂&#xff0c;下面以图示的方法来理解RSA加密解密的过程 以上过程中因为HACK无法得到p,q信息&#xff0c;也就是无法计算出d , 导致了无法解密 c 得到 m (n,e) 公钥 (d,n) 私钥 (p,q,n,e) 生成的加密必要信息 必要的公式 c ≡ me mod n ----------->…

基于栈结构的非递归二叉树结点关键字输出算法

基于栈结构的非递归二叉树结点关键字输出算法 一、引言二、二叉树基本概念三、非递归遍历算法基础四、算法设计五、算法实现六、C代码示例七、算法分析八、优化与讨论 一、引言 在计算机科学中&#xff0c;二叉树是一种重要的数据结构&#xff0c;它广泛应用于各种算法和数据结…