【Java学习】Stream流详解
所属专栏:Java学习

Stream流是JDK 8引入的一个概念,它提供了一种高效且表达力强的方式来处理数据集合(如List、Set等)或数组。Stream API可以以声明性方式(指定做什么)来处理数据序列。流操作可以被分为两大类:中间操作(Intermediate Operations)和终端操作(Terminal Operations)。
🍁1. Stream流的适用对象
先得到一条Stream流,并把数据放上去,再进行中间操作和终端操作
| 获取方式 | 方法名 | 说明 |
| 单列集合 | default Stream<E>stream() | Collection中的默认方法 |
| 双列集合 | 无 | 无法直接使用Stream流 |
| 数组 | public static <T> Stream<T> stream(T[] array) | Arrays工具类中的静态方法 |
| 一堆零散数据 | public static <T> Stream<T> of(T...values) | Stream接口中的静态方法 |
先来看单列集合的例子:
public class Demo1 {public static void main(String[] args) {ArrayList<String> arrayList = new ArrayList<>();Collections.addAll(arrayList, "a", "b", "c", "d", "e");// 获取Stream流,把集合中的数据放到流上Stream<String> stream1 = arrayList.stream();//内部类方式打印stream1.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.print(s);}});System.out.println();//获取流之后直接通过lambda表达式进行打印arrayList.stream().forEach(s -> System.out.print(s));}
}
对于双列集合,需要通过keySet() 或 entrySet() 转化为单列集合,再获取Stream
public class Demo2 {public static void main(String[] args) {HashMap<String,Integer> hashMap = new HashMap<>();hashMap.put("aaa",1);hashMap.put("bbb",2);hashMap.put("ccc",3);hashMap.put("ddd",4);//双列集合第一种获取Stream流hashMap.keySet().stream().forEach(s -> System.out.print(s + " "));System.out.println();//双列集合第二种获取hashMap.entrySet().stream().forEach(s -> System.out.print(s + " "));}
}
数组获取Stream流:
public class Demo3 {public static void main(String[] args) {int[] arr1 = {1, 2, 3, 4, 5};String[] arr2 = {"a", "b", "c", "d"};//获取Stream流Arrays.stream(arr1).forEach(s-> System.out.print(s + " "));System.out.println();//数组中是引用型数据类型也可以获取Stream流Arrays.stream(arr2).forEach(s -> System.out.print(s + " "));}
}
对于不存储在数组或集合中的零散数据,可以直接通过Stream接口中的静态方法获取
public class Demo4 {public static void main(String[] args) {Stream.of(1,2,3,4,5).forEach(s-> System.out.print(s + " "));System.out.println();Stream.of("a","b","c").forEach(s-> System.out.print(s + " "));}
}
🍁2. 中间方法

中间操作:中间操作可以返回流本身,因此可以链式调用多个中间操作,中间操作可以是对流的过滤(如filter)、映射(如map)、排序(如sorted)等
在上面的中间方法时,只会修改Stream流中的数据,不会影响原来集合或数组中的数据,并且原来的流只能使用一次
🍁2.1 filter()

filter 的参数 Predicate 是一个函数式接口 ,所以可以先使用匿名内部类的方式,再用 lambda 表达式
public class Demo5 {public static void main(String[] args) {ArrayList<String> arrayList = new ArrayList<>();Collections.addAll(arrayList, "aaa", "abc", "acb", "aa", "bb", "cc");//fitlter 过滤 把a开头的留下,其余数据不要arrayList.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {//返回值为true,当前数据留下,返回值为false,当前数据舍弃return s.startsWith("a");}}).forEach(s -> System.out.print(s + " "));System.out.println();// lambda表达式的形式arrayList.stream().filter(s -> s.startsWith("a")).forEach(s -> System.out.print(s + " "));System.out.println();//把stream流暂时接收的方式Stream<String> stream1 = arrayList.stream().filter(s -> s.startsWith("a"));stream1.forEach(s -> System.out.print(s + " "));}
}
由于Stream流只能用一次,如果之前的流已经被使用过,再次使用就会报错

所以说,由于只能使用一次,再用一个变量取接收也没有什么意义,直接使用链式编程就可以了
并且,使用流之后,原来集合中的元素也不会改变

🍁2.2 limit() 和 skip()
/* limit() 获取前面几个元素skip() 跳过几个元素*/arrayList.stream().limit(3).forEach(s -> System.out.print(s + " "));System.out.println();arrayList.stream().skip(3).forEach(s -> System.out.print(s + " "));

🍁2.3 distinct()和concat()
distinct()去重是依赖hashCode()和equals()方法的,所以如果是自定义类型,要手动的重写这两个方法
public class Demo6 {public static void main(String[] args) {ArrayList<String> arrayList1 = new ArrayList<>();Collections.addAll(arrayList1, "aaa", "aaa", "acb", "aa", "bb", "cc");ArrayList<String> arrayList2 = new ArrayList<>();Collections.addAll(arrayList2,"dd","ee");//去重arrayList1.stream().distinct().forEach(s -> System.out.print(s + " "));System.out.println();//流的合并Stream.concat(arrayList1.stream(),arrayList2.stream()).forEach(s -> System.out.print(s + " "));}
}

🍁2.4 map()
需求:获取集合中的数字部分
首先调用split方法进行分割,得到数字部分之后再转换为整型
public class Demo7 {public static void main(String[] args) {ArrayList<String> arrayList = new ArrayList<>();Collections.addAll(arrayList, "aaa-11", "acb-22", "aa-33", "bb-44", "cc-55");// 获取集合中的数字部分arrayList.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {//使用split进行分割String[] arr = s.split("-");//获取数字部分String num = arr[1];//转换为int类型int ans = Integer.parseInt(num);return ans;}}).forEach(s -> System.out.print(s + " "));System.out.println();//lambda表达式arrayList.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(s -> System.out.print(s + " "));}
}

🍁3. 终结方法
| 名称 | 说明 |
| void forEach(Consumer action) | 遍历 |
| long count() | 统计 |
| toArray() | 收集流中的数据,放到数组中 |
| collect(Collector collector) | 收集流中的数据,放到集合中 |
🍁3.1 forEach()和count()
forEach方法在之前已经演示过了,就是进行遍历的

forEach中的参数Consumer也是一个函数式接口,也可以先使用匿名内部类的方式,再用 lambda 表达式
public class Demo8 {public static void main(String[] args) {ArrayList<String> arrayList = new ArrayList<>();Collections.addAll(arrayList, "aaa", "aaa", "acb", "aa", "bb", "cc");arrayList.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.print(s + " ");}});System.out.println();arrayList.forEach(s-> System.out.print(s + " "));System.out.println();//统计个数long l = arrayList.stream().count();System.out.println(l);}
}
count() 的返回值为long类型的,可以定义一个变量进行接收
🍁3.2 toArray()
toArray()是收集流里面的数据放在数组中

toArray()方法有两种返回类型,一种是Object类型的,另一种是指定类型的,Object类型的比较简单,直接用Object类型的变量来接收就可以了
public class Demo9 {public static void main(String[] args) {ArrayList<String> arrayList = new ArrayList<>();Collections.addAll(arrayList, "aaa", "aaa", "acb", "aa", "bb", "cc");Object[] array1 = arrayList.stream().toArray();System.out.println(Arrays.toString(array1));}
}
接下来看指定类型

toArray方法的参数也是一个函数式接口,还是使用匿名内部类和lambda表达式两种方式演示
public class Demo9 {public static void main(String[] args) {ArrayList<String> arrayList = new ArrayList<>();Collections.addAll(arrayList, "aaa", "aaa", "acb", "aa", "bb", "cc");//IntFunction的泛型:具体类型的数组//apply方法的形参:流中数据的个数,返回的数组的长度要一致//返回值就是具体类型的数组String[] array2 = arrayList.stream().toArray(new IntFunction<String[]>() {@Overridepublic String[] apply(int value) {return new String[value];}});System.out.println(Arrays.toString(array2));//lambda表达式String[] array = arrayList.stream().toArray(value -> new String[value]);System.out.println(Arrays.toString(array));}
}
IntFunction的泛型是具体类型的数组
apply方法的形参表示流中数据的个数,返回的数组的长度要一致,最后的返回值就是具体类型的数组

🍁3.3 collect()
collect() 方法就是收集流里面的数据放到集合中,下面先来演示收集到List和Set集合中的例子
public class Demo10 {public static void main(String[] args) {ArrayList<String> arrayList = new ArrayList<>();Collections.addAll(arrayList, "张三-男-23", "李四-男-21", "王五-女-22", "钱七-女-22");// 把所有男性收集起来//收集到List集合中List<String> list = arrayList.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toList());//收集到Set集合中Set<String> set = arrayList.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());}
}
收集到List和Set集合中的数据的区别还是和List和Set集合的区别一样的,Set集合中不能有重复的元素,如果流中收集的数据存在重复的数据,在收集到Set集合之后就会进行去重
接下来看Map集合,由于Map集合是一个双列集合,所以需要指定键和值的生成规则
这里的生成规则比较复杂
//收集到Map集合中/*** toMap : 参数一表示键的生成规则* 参数二表示值的生成规则* 参数一:* Function 泛型一:表示流中的数据类型* 泛型二:表示Map集合中键的类型* 方法 apply 形参:表示流中的每一个数据* 方法体:生成键的代码* 返回值:已经生成的键**/Map<String, Integer> map1 = arrayList.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toMap(new Function<String, String>() {@Overridepublic String apply(String s) {return s.split("-")[0];}}, new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s.split("-")[2]);}}));System.out.println(map1);
//lambda表达式Map<String, Integer> map2 = arrayList.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.parseInt(s.split("-")[2])));System.out.println(map2);
由于Map集合中是不能有重复的键的,所以如果Stream流获取的键中存在了重的元素,就会报错
🍁4. Stream流的作用和使用步骤总结
作用:Stream流就是结合了lambda表达式,简化集合和数组的操作
使用步骤:
1. 获取Stream流对象
2.使用中间方法处理数据
3.使用终结方法处理数据

相关文章:
【Java学习】Stream流详解
所属专栏:Java学习 Stream流是JDK 8引入的一个概念,它提供了一种高效且表达力强的方式来处理数据集合(如List、Set等)或数组。Stream API可以以声明性方式(指定做什么)来处理数据序列。流操作可以被分为两大…...
Oracle(69)什么是表压缩(Table Compression)?
表压缩(Table Compression)是一种数据库优化技术,用于减少表数据的存储空间和提高I/O性能。通过压缩表数据,可以显著减少存储需求,并在某些情况下提高查询性能,特别是对于只读或主要是读取操作的表。表压缩…...
java JUC编程
Java并发工具包(JUC),全称Java Util Concurrent,是Java提供的一个用于构建多线程应用程序的工具包,位于java.util.concurrent包及其子包中。 并发编程主要解决以下三个经典问题: 1. **原子性问题…...
vue3+element-plus表格分页选中加默认回显选中
1.需求 某个表单需要选择多条数据,点击选择按钮,弹框出来一个分页列表,选择多条数据,外面表单中显示选中的数据,可以删除数据,再次点击按钮,回显当前选中的数据。 2.解决办法 1.el-table加ro…...
Erupt 项目搭建
创建Spring Boot项目 Maven依赖 Spring Boot版本为 2.7.10,erupt版本为 1.12.14 erupt版本要与Spring Boot版本适配,3.x.x版本Spring Boot暂不适用说是 <properties><erupt.version>1.12.14</erupt.version></properties> <…...
HarmonyOS Next 系列之列表下拉刷新和触底加载更多数据实现(十一)
系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现(一) HarmonyOS Next 系列之验证码输入组件实现(二) HarmonyOS Next 系列之底部标签栏TabBar实现(三) HarmonyOS Next 系列之HTTP请求封装和Token…...
比特位的计算
给你一个整数 n ,对于 0 < i < n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n 1 的数组 ans 作为答案。 示例 1: 输入:n 2 输出:[0,1,1] 解释: 0 --> 0 1 --> …...
SQLAlchemy 学习笔记
通信类型:AF_INET 协议家族一般是表示TCP通信的SOC_STREAM和UDP通信的SOCK_DGRAM。对于TCP通信,建立socket连接,: s socket.socket(socket.AF_INET, socket.SOCK_STREAM)连接socket, s.connect((host,port))socket通信…...
Linux内核分析(调度类和调度实体)
文章目录 前言一、调度类1. stop_sched_class2. dl_sched_class3. rt_sched_class4. fair_sched_class5. idle_sched_class总结 二、调度类中的操作函数三、调度实体 前言 调度是操作系统内核的一个关键职责,它涉及到如何合理分配CPU时间给不同的进程或线程。在Lin…...
用输入输出流(I/O)流,递归复制和删除多级文件
一、(I/O)流递归复制一个文件 第一种: else if语句过多,看起来冗余,优点:多级文件一次性复制完整 import java.io.*;//数据源:src/main/java/day15_8_13/haha //目标;src/main/java/LaJi pub…...
kafka监控工具EFAK
kafka监控工具(EFAK) 1、下载2、解压3、配置3.1、安装数据库,需要mysql是,并创建ke数据库3.2、修改配置文件 4、启动4.1、启动zookeeper4.2、启动kafka4.3、启动EFAK 5、访问http://ip:8048 github地址:https://github…...
Page与自定义Components生命周期
自定义组件 自定义组件一般可以用component,装饰,在结构体里面用build方法定义UI,或者用builder装饰一个方法,来作为自定义组件的构造方法 而页面page一般用Entry,和component结合起来使用 页面生命周期方法: onPageShow:页面每次显示时触发 onPageHid…...
Chain of Thought (CoT) 系列论文:大模型思维链,提升 LLM 的推理能力
文章目录 1. COT:Chain of Thought1. 研究背景2. CoT的原理3. CoT Prompt 1. COT:Chain of Thought COT 是 2022.01 由 google 提出的针对提升 LLM 的推理能力的 Prompt Engineering 方法。 paper: Chain-of-Thought Prompting Elicits Re…...
已解决:java.net.BindException: 地址已在使用
1. 问题描述 java.net.BindException: 地址已在使用 是一种常见的网络异常,通常在服务器程序尝试绑定到一个已经被占用的端口或地址时出现。具体的异常信息可能如下: java.net.BindException: Address already in use: JVM_Bind或 java.net.BindExcep…...
看书标记【数据科学:R语言实战 8】
看书标记——R语言 Chapter 8 数据可视化——绘图8.1 功能包8.2 散点图8.2.1 回归线8.2.2 lowess线条8.2.3 scatterplot函数8.2.4 Scatterplot矩阵1.splom——展示矩阵数据2.cpairs——绘图矩阵图 8.2.5 密度散点图 8.3 直方图和条形图8.3.1 条形图8.3.2 直方图 8.3.3 ggplot28…...
STM32标准库学习笔记-1.基础知识
STM32介绍: STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器。 ARM的含义: 公司名称:ARM公司成立于1990年,全称是Advanced RISC Machines(RISC:Reduced Instruction Set Computer 精简指令集计算机 相对应有C…...
Nginx:高效HTTP服务器与反向代理
Nginx:高效HTTP服务器与反向代理 1、核心特点2、应用场景 💖The Begin💖点点关注,收藏不迷路💖 Nginx,一个开源的HTTP服务器与反向代理工具,因其高性能、低资源消耗而备受推崇。以下是Nginx的几…...
vue3二次封装element-puls
将表单的通用信息给设置出来 如: label 的提示信息 , type 的类型 // 定义表单的配置项 const formConfig{ formItems:[ { type:"input", label:"用户ID", placeholder:"请输入用户ID" } ] } 页面配置如 <template v-for"(it…...
在CentOS 7上安装Apache Tomcat 8的方法
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 介绍 Apache Tomcat 是一个用于提供 Java 应用程序的 Web 服务器和 Servlet 容器。Tomcat 是由 Apache 软件基金会发布的 Java Servlet…...
深入理解分布式事务中的三阶段提交(3PC),什么是3PC,3PC原理是怎样?3PC的优化?
在上一篇文章中,我们详细介绍了分布式事务中的两阶段提交,以及知道了两阶段提交存在一定的问题 深入理解分布式事务中的两阶段提交(2PC),什么是2PC,2PC原理是怎样?2PC有没有什么问题࿱…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

