Java的Stream流:文件处理、排序与串并行流的全面指南
Java的Stream流:文件处理、排序与串并行流的全面指南
Java 8 引入了 Stream API,这是一个用于处理集合数据的强大工具,它提供了一种声明式的方式来进行聚合操作。Stream 不是一个数据结构,而是一种对数据进行操作的抽象,允许开发者以一种更简洁、易读的方式来表达复杂的查询逻辑。下面我们将详细介绍 Java Stream 的概念、特性以及如何使用它。
1 Stream 的基本概念
Stream 是一个来自源的数据元素序列,支持顺序和并行聚合操作。它可以看作是高级版本的 Iterator,但是与 Iterator 不同的是,Stream 操作可以链式调用,从而形成一系列的操作流水线。此外,Stream 的操作不会修改源数据,而是生成新的结果。
1.2 Stream 的创建
创建 Stream 有多种方式:
- 从集合创建:大多数集合类都提供了
stream()和parallelStream()方法来创建串行流或并行流。 - 通过静态方法创建:
Stream.of()可以接受不定数量的参数来创建流;Stream.generate()和Stream.iterate()可以生成无限流,通常需要结合limit()来限制大小。 - 从数组创建:可以通过
Arrays.stream(array)或者直接调用数组上的stream()方法来创建流。 - 文件读取:
BufferedReader.lines()可以将文件的每一行转换成流中的元素。 - 正则表达式分割字符串:
Pattern.splitAsStream()可以根据指定的分隔符将字符串拆分成流。
1.3 中间操作
中间操作是指那些返回另一个 Stream 的操作,它们本身不会触发任何计算,只有当终端操作被执行时才会真正开始处理数据。常见的中间操作包括:
- filter:过滤掉不符合条件的元素。
- map:对每个元素应用一个函数,并返回一个新的 Stream。
- flatMap:对每个元素应用一个函数,该函数返回一个 Stream,然后将所有这些 Stream 扁平化为一个单独的 Stream。
- distinct:去除重复元素。
- sorted:对元素排序,可以选择自然排序或自定义比较器。
- peek:对每个元素执行副作用操作(如打印),但不改变流的内容。
1.4 终端操作
一旦执行了终端操作,Stream 就会被消耗掉,不能再被使用。常见的终端操作有:
- forEach:遍历流中的每一个元素。
- collect:将流中的元素收集到集合中,如 List 或 Set。
- reduce:通过某种方式减少流中的元素,例如求和或乘积。
- count:统计流中元素的数量。
- min/max:找到最小值/最大值。
- anyMatch/allMatch/noneMatch:检查是否至少有一个/所有/没有元素满足给定的谓词。
2 基本使用示例
示例1 筛选大于等于 10 的整数
List<Integer> numbers = Arrays.asList(5, 10, 15, 20, 25, 30);
numbers.stream().filter(num -> num >= 10).forEach(System.out::println);
这段代码会输出 10, 15, 20, 25, 30,因为这些都是大于等于 10 的数字。
示例2 提取员工姓名
List<Employee> employees = Arrays.asList(new Employee("Alice", 25),new Employee("Bob", 30),new Employee("Charlie", 35)
);
employees.stream().map(Employee::getName).forEach(System.out::println);
这里我们使用 map 操作提取了每个员工的名字,并打印出来。
示例3 去重
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 2, 3, 5, 1, 6);
numbers.stream().distinct().forEach(System.out::println);
这段代码会输出 1, 2, 3, 4, 5, 6,因为 distinct 操作已经移除了重复的元素。
3 文件读取与 Stream 结合
在 Java 8 中,Files.lines() 方法提供了一种简单而有效的方式来逐行读取文件内容,并将其转换为 Stream。这使得我们可以利用 Stream 的强大功能来处理文件中的每一行数据,例如过滤、映射、排序等。下面我们将通过几个具体的示例来展示如何结合文件读取操作使用 Stream。
示例 4:逐行读取文件并打印
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;public class 读取文件示例 {public static void main(String[] args) {try (Stream<String> 行流 = Files.lines(Paths.get("data.txt"))) {行流.forEach(System.out::println);} catch (IOException e) {System.err.println("读取文件时发生错误: " + e.getMessage());}}
}
这段代码展示了如何使用 Files.lines() 方法逐行读取文件 data.txt 并打印每一行的内容。try-with-resources 语句确保了流在使用完毕后会被自动关闭,避免资源泄露。
示例 5:查找包含特定关键词的行
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Optional;public class 查找关键词示例 {public static void main(String[] args) {try (Stream<String> 行流 = Files.lines(Paths.get("data.txt"))) {Optional<String> 包含密码的行 = 行流.filter(行 -> 行.contains("密码")).findFirst();if (包含密码的行.isPresent()) {System.out.println("找到包含 '密码' 的行: " + 包含密码的行.get());} else {System.out.println("没有行包含 '密码'.");}} catch (IOException e) {System.err.println("读取文件时发生错误: " + e.getMessage());}}
}
此示例展示了如何使用 filter 和 findFirst 方法来查找文件中包含特定关键词(如 “密码”)的第一行,并将其打印出来。如果找不到符合条件的行,则输出相应的提示信息。
示例 6:统计文件中单词的数量
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.regex.Pattern;
import java.util.stream.Collectors;public class 统计单词数量示例 {public static void main(String[] args) throws IOException {long 单词总数 = Files.lines(Paths.get("data.txt")).flatMap(Pattern.compile("\\s+")::splitAsStream).count();System.out.println("总共有 " + 单词总数 + " 个单词");}
}
在这个例子中,我们使用 flatMap 方法结合正则表达式来分割每一行文本,从而得到一个包含所有单词的流。然后,我们使用 count 方法统计总共有多少个单词。这种方法非常适合处理大文件,因为它可以在不加载整个文件到内存的情况下完成任务。
示例 7:按字母顺序排序并去重后的单词列表
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;public class 排序去重单词示例 {public static void main(String[] args) throws IOException {List<String> 排序后的唯一单词 = Files.lines(Paths.get("data.txt")).flatMap(Pattern.compile("\\s+")::splitAsStream).distinct().sorted().collect(Collectors.toList());System.out.println("按字母顺序排序并去重后的单词: " + 排序后的唯一单词);}
}
这段代码展示了如何结合 flatMap、distinct 和 sorted 方法来获取文件中按字母顺序排序且去重后的单词列表。最终结果被收集到一个 List<String> 中,并打印出来。这种方法可以有效地去除重复项,并对结果进行排序,非常适合用于文本分析等场景。
5 串行流与并行流
串行流是指所有操作都在单个线程上依次执行,而并行流则是指操作可以在多个线程上并发执行。并行流可以在多核处理器上提高效率,但是需要注意,并不是所有的操作都适合并行化,而且并行流可能会带来额外的开销。因此,在选择使用串行流还是并行流时,应该根据具体的应用场景做出权衡。
示例 8:使用串行流计算文件中单词的总长度
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.regex.Pattern;public class 串行流计算单词总长度示例 {public static void main(String[] args) throws IOException {long 单词总长度 = Files.lines(Paths.get("data.txt")).flatMap(Pattern.compile("\\s+")::splitAsStream).mapToInt(String::length).sum();System.out.println("所有单词的总长度: " + 单词总长度);}
}
这段代码展示了如何使用串行流来计算文件中所有单词的总长度。flatMap 方法将每一行文本拆分为多个单词,mapToInt 方法将每个单词映射为其长度,最后使用 sum 方法计算所有单词长度的总和。
示例 9:使用并行流计算文件中单词的总长度
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.regex.Pattern;public class 并行流计算单词总长度示例 {public static void main(String[] args) throws IOException {long 单词总长度 = Files.lines(Paths.get("data.txt")).parallel() // 使用并行流.flatMap(Pattern.compile("\\s+")::splitAsStream).mapToInt(String::length).sum();System.out.println("所有单词的总长度: " + 单词总长度);}
}
在这段代码中,我们通过调用 parallel() 方法将串行流转换为并行流,从而允许 JVM 在多核处理器上并行处理文件中的每一行。需要注意的是,并行流的使用可能会导致结果的顺序发生变化,但在本例中,由于我们只关心单词长度的总和,因此顺序不影响最终结果。
6 性能考量
虽然 Stream 提供了非常方便的操作接口,但在某些情况下可能会影响性能,特别是对于大规模数据集。并行流可以在多核处理器上提高效率,但是需要注意,并不是所有的操作都适合并行化,而且并行流可能会带来额外的开销。因此,在选择使用串行流还是并行流时,应该根据具体的应用场景做出权衡。
7 使用 Stream 的注意事项
惰性求值:Stream 的中间操作是惰性的,只有遇到终端操作时才会触发实际的计算。
不可重用:Stream 的一旦被消费(即执行了终端操作),便不能再次使用。如果需要多次操作同一组数据,可以创建多个流对象。
线程安全:虽然并行流可以在多线程环境中工作,但这并不意味着它是线程安全的。对于非线程安全的操作,仍然需要采取适当的同步措施。
总结
通过上述示例,我们可以看到 Java Stream API 提供了一种简洁且强大的方式来处理集合数据。无论是文件读取、简单排序还是串行流与并行流的选择,Stream 都能够帮助开发者写出更加优雅和高效的代码。然而,在实际开发中,我们应该根据具体的需求和数据量来决定是否使用 Stream,以及选择合适的流类型,以确保最佳的性能和可维护性。
相关文章:
Java的Stream流:文件处理、排序与串并行流的全面指南
Java的Stream流:文件处理、排序与串并行流的全面指南 Java 8 引入了 Stream API,这是一个用于处理集合数据的强大工具,它提供了一种声明式的方式来进行聚合操作。Stream 不是一个数据结构,而是一种对数据进行操作的抽象ÿ…...
[Maven]下载安装、使用与简介
很多框架的下载使用的流程和思路是差不多的,这里以maven做详细介绍。 下载安装与配置变量 下载 首先,我们要使用maven,必须先下载它的相关文件。想要下载,我们可以直接搜索maven。找到它的官网。这里不绕弯子,直接给出…...
056 WXML+ WXSS+PHP+LW+校园配送商城微信小程序开发与设计 源码 文档 全套资料
校园配送微信小程序 1.项目描述2. 1.绪论3.项目技术与功能4.界面展示5.源码获取 1.项目描述 摘 要 近几年来,随着互联网和电子商务的快速发展和普及,改变了人们日常消费模式。尤其是移动互联网的相结合,使得人们日常生活中更多的是通过手机移…...
Python 在同一/或不同PPT文档之间复制幻灯片
复制幻灯片可以帮助我们更高效地完成工作,节省大量的制作时间。通过复制现有的幻灯片,可以快速创建新的演示文稿,而无需重新设计板式样式等。此外,复制幻灯片还可以帮助我们保持内容的一致性,使整个PPT演示文稿看起来更…...
C#生成CSR(CertificateSigningRequest)和密钥
使用C#原生生成CSR(CertificateSigningRequest)和密钥。 生成的私钥妥善保存,丢失无法找回。 调用 var contents X509Helper.SigningRequestHelper.CreateSigningRequest("yourdomain.com", ["*.yourdomain.com"], X509Helper.AsymmetricAl…...
Docker 安装 Oracle创建表空间并导入数据库
一、Docker 安装Oracle 1、检查docker 版本 2、docker 下载镜像 3、 docker启动容器 4、 进入容器内部 5、安装成功,使用客户端工具连接 二、创建数据库用户与表空间 1、查询数据库文件位置 2、创建表空间 3、创建用户 4、设置权限 三、导出数据库DMP …...
elementui table子级tree懒加载bug
1. 删除子级刷新列表子级依然显示 2.更新状态子级列表未刷新 3.编辑子级后刷新页面显示状态未变更 el-table 树表格load源码 首先,load可以执行,但是只剩一个子节点就有问题,那么就直接可以定位bug在load方法里: 文件路径&am…...
AI与低代码技术融合:如何加速企业智能化应用开发?
引言 随着全球数字化转型的步伐加快,企业在智能化应用开发方面面临着前所未有的挑战和机遇。传统的软件开发方式往往需要大量的技术人员、时间和资源,而在瞬息万变的市场环境中,这种模式显得效率低下且难以满足企业快速迭代和创新的需求。 与…...
【C#】新建窗体文件,Form、UserControl
从用途、功能性和架构方面进行描述。 1. 继承自 Form 的窗体(通常是窗口): 在 C# 中,Form 是用于创建应用程序的主窗口或对话框窗口的类。当您继承自 Form 时,您创建的是一个完整的窗口,可以显示内容、与…...
ansible学习笔记之02command模块与shell模块
目录 1、概述 2、模块介绍 2.1 command模块 2.2 shell模块 2.3 小结 3、实验 3.1 测试ls命令 3.2 测试环境变量 3.3 测试操作符">" 1、概述 本文介绍ansible的command模块与shell模块,并通过实验比对两个模块的异同。 2、模块介绍 2.1…...
在Docker中部署禅道,亲测可用
1、确保centos中已安装docker docker -v 2、启动docker systemctl start docker 3、可设置docker开机启动 systemctl enable docker.service 4、获取最新版禅道开源版镜像 docker pull idoop/zentao 5、运行镜像生成禅道容器【创建 /data/www /data/data 目录】 doc…...
C++(十二)
前言: 本文将进一步讲解C中,条件判断语句以及它是如何运行的以及内部逻辑。 一,if-else,if-else语句。 在if语句中,只能判断两个条件的变量,若想实现判断两个以上条件的变体,就需要使用if-else,if-else语…...
【数学建模】线性规划问题及Matlab求解
问题一 题目: 求解下列线性规划问题 解答: 先将题目中求最大值转化为求最小值,则有 我们就可以得到系数列向量: 我们对问题中所给出的不等式约束进行标准化则得到了 就有不等式约束条件下的变系数矩阵和常系数矩阵分别为: 等式…...
【JavaWeb后端学习笔记】Spring全局异常处理器
在程序运行时,不可避免的会出现异常。在三层开发架构中,当Mapper层出现异常、如果不进行处理会抛给Service层,如果Service层也不处理则会抛给Controller层,通常Controller层有许多接口,如果对每个接口单独处理异常&…...
PT8M2102 触控型 8Bit MCU
1 产品概述 ● PT8M2102 是一款基于 RISC 内核的8位 MTP 单片机,内部集成了电容式触摸感应模块、TIMER,PWM、LVR、LVD、WDT等外设,其主要用作触摸按键开关,广泛适用于触控调光、电子玩具、消费电子、家用电器等领域,具…...
4. React 性能优化技巧:如何让你的应用更快
在构建大型应用时,性能优化是一个非常重要的话题。React 提供了许多优化工具,帮助我们提高应用的渲染速度和响应能力。本文将分享一些常见的 React 性能优化技巧。 4.1. 使用 React.memo 缓存组件 当组件的 props 没有变化时,React 默认不会…...
pytest中使用conftest做测试前置和参数化
pytest中比较高阶的应用是,使用conftest去做测试前置工作、测试收尾工作和参数化。conftest是pytest的一个组件,用于配置测试环境和参数。通过conftest, 可以创建一个可复用的测试配置文件,以便在多个测试模块之间共享配置信息。即࿰…...
Spring Boot 中使用 @Transactional 注解配置事务管理
事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污…...
MATLAB 建筑顶面面积计算(95)
MATLAB 建筑顶面面积计算(95) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 根据给出的建筑顶面点云,计算建筑面积,具体的方法实现和结果如下: 二、算法实现 1.代码 代码如下(示例): % 从 PLY 文件读取点云数据 filename = D:\shuju\屋顶2.ply; % 替换为你的…...
Linux网络编程之---组播和广播
一.组播 1.概述 单播地址标识单个IP 接口,广播地址标识某个子网的所有IP 接口, 多播地址标识一组IP 接口。单播和广播是寻址方案的两个极端(要么单个要么全部), 多播则意在两者之间提供一种折中方案。多播数据报只应该由对它感兴趣的接口接收…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
深入理解 React 样式方案
React 的样式方案较多,在应用开发初期,开发者需要根据项目业务具体情况选择对应样式方案。React 样式方案主要有: 1. 内联样式 2. module css 3. css in js 4. tailwind css 这些方案中,均有各自的优势和缺点。 1. 方案优劣势 1. 内联样式: 简单直观,适合动态样式和…...
