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());}}
}

此示例展示了如何使用 filterfindFirst 方法来查找文件中包含特定关键词(如 “密码”)的第一行,并将其打印出来。如果找不到符合条件的行,则输出相应的提示信息。

示例 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("按字母顺序排序并去重后的单词: " + 排序后的唯一单词);}
}

这段代码展示了如何结合 flatMapdistinctsorted 方法来获取文件中按字母顺序排序且去重后的单词列表。最终结果被收集到一个 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,以及选择合适的流类型,以确保最佳的性能和可维护性。

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

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

相关文章

运维工程师.云计算工程师指令集锦

LINUX简介与安装 一、Linux基础认知知识&#xff1a; 多使用者、多任务、多层次 Linux&#xff1a;开源、免费、安全、稳定 Linux中一切皆文件 Linux严格区分大小写 Linux文件命名规则&#xff1a; ①除了/之外&#xff0c;所有字符都合法&#xff1b; ②有些字符最好不用&…

波特图方法

在电路设计中&#xff0c;波特图为最常用的稳定性余量判断方法&#xff0c;波特图的根源是如何来的&#xff0c;却鲜有人知。 本章节串联了奈奎斯特和波特图的渊源&#xff0c;给出了其对应关系和波特图相应的稳定性余量。 理论贯通&#xff0c;不在于精确绘…

React 组件中 State 的定义、使用及正确更新方式

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;React篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来React篇专栏内容React 组件中 State 的定义、使用及正确更新方式 前言 在 React 应用开发中&#xff0c;state …

C++(十二)

前言&#xff1a; 本文将进一步讲解C中&#xff0c;条件判断语句以及它是如何运行的以及内部逻辑。 一&#xff0c;if-else,if-else语句。 在if语句中&#xff0c;只能判断两个条件的变量&#xff0c;若想实现判断两个以上条件的变体&#xff0c;就需要使用if-else,if-else语…

查询产品所涉及的表有(product、product_admin_mapping)

文章目录 1、ProductController2、AdminCommonService3、ProductApiService4、ProductCommonService5、ProductSqlService1. 完整SQL分析可选部分&#xff08;条件筛选&#xff09;&#xff1a; 2. 涉及的表3. 总结4. 功能概述 查询指定管理员下所有产品所涉及的表&#xff1f;…

Java应用服务器JVM配置与优化全面指南

Java应用服务器JVM配置与优化全面指南 1. JVM基础知识 Java虚拟机&#xff08;JVM&#xff09;是Java平台的核心&#xff0c;负责执行Java字节码。理解JVM的基本组成和工作原理是进行有效优化的基础。 1.1 JVM主要组件 类加载器&#xff1a;负责加载、链接和初始化类文件。…

游戏引擎学习第36天

仓库 :https://gitee.com/mrxiao_com/2d_game 回顾之前的内容 在这个程序中&#xff0c;目标是通过手动编写代码来从头开始制作一个完整的游戏。整个过程不使用任何库或现成的游戏引擎&#xff0c;这样做的目的是为了能够全面了解游戏执行的每一个细节。开发过程中&#xff0…

【SpringMVC】用户登录器项目,加法计算器项目的实现

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;用户登录项目实现 1&#xff1a;需求 2&#xff1a;准备工作 &#xff08;1&#xf…

3.5 认识决策树

3.5 认识决策树 3.5.1 认识决策树 如何高效的进行决策&#xff1f; 特征的先后顺序 3.5.2 决策树分类原理详解 已知有四个特征&#xff0c;预测 是否贷款给某个人。 先看房子&#xff0c;再看工作&#xff0c;是否贷款。 年龄&#xff0c;信贷情况&#xff0c;工作&#…

MyBatis-Plus分页查询方式

分页查询基本方式 SpringBootTest(classes LearningApplication.class) public class MPTest {AutowiredILearningLessonService lessonService;Testpublic void test(){/*** Page<LearningLesson>&#xff1a;MyBatisPlus提供的分页对象* 1&#xff1a;当前页数* 2&am…

AI智能体Prompt预设词指令大全+GPTs应用使用

AI智能体使用指南 直接复制在AI工具助手中使用&#xff08;提问前&#xff09; 可前往SparkAi系统用户官网进行直接使用 SparkAI系统介绍文档&#xff1a;Docs 常见AI智能体GPTs应用大全在线使用 自定义添加制作AI智能体进行使用&#xff1a; 文章润色器 你是一位具有敏锐洞察…

MYSQL字符集和校对规则

文章目录 MYSQL字符集MYSQL默认字符集MySQL常见字符集 MYSQL校对规则校对规则总结 MYSQL字符集 UTF(Unicode Tranformation Format)是Unicode字符集规范的其中一个编码方式。 各字符编码详解可参考&#xff1a;字符编码发展历史 MYSQL默认字符集 5.7版本及之前&#xff1a;…

K8S,StatefulSet

有状态应用 Deployment实际上并不足以覆盖所有的应用编排问题&#xff1f; 分布式应用&#xff0c;它的多个实例之间&#xff0c;往往有依赖关系&#xff0c;比如&#xff1a;主从关系、主备关系。 还有就是数据存储类应用&#xff0c;它的多个实例&#xff0c;往往都会在本地…

子类有多个父类的情况下Super不支持指定父类来调用方法

1、Super使用方法 super()函数在Python中用于调用父类的方法。它返回一个代理对象&#xff0c;可以通过该对象调用父类的方法。 要使用super()方法&#xff0c;需要在子类的方法中调用super()&#xff0c;并指定子类本身以及方法的名称。这样就可以在子类中调用父类的方法。 …

Mac电脑如何解压rar压缩包

group 868373192 second group 277356808 在 macOS 上解压 RAR 文件&#xff0c;你可以使用以下几种方法&#xff1a; 方法 1: 使用 The Unarchiver 下载并安装 The Unarchiver: 你可以从 Mac App Store 下载 The Unarchiver。 解压 RAR 文件: 找到你想要解压的 RAR 文件。 …

《深入浅出HTTPS》读书笔记(16):消息验证码算法分类

MAC算法有两种形式&#xff0c;分别是CBC-MAC算法和HMAC算法。 CBC-MAC算法从块密码算法的CBC分组模式演变而来&#xff0c;简单地说就是最后一个密文分组的值就是MAC值。 HMAC&#xff08;Hash-based Message Authentication Code&#xff09;算法使用Hash算法作为加密基元&am…

又一个ansible例子

这个例子有点复杂&#xff0c;他在被控端上采集CPU 内存和磁盘利用率&#xff0c;并且以模板的形式保存在被控端&#xff0c;最后再把这个结果文件从被控端取回来。综合用到了shell、register、template和fetch4个模块 --- - name: get cpu mem and disk hosts: all tasks…

使用国内镜像源加速Qt“更新/安装”的方法

QT更新/安装时&#xff0c;国外源下载很慢&#xff0c;国内镜像源也因网络环境的不同而速度各异&#xff0c;下文给出国内镜像源的配置方法。 一、命令行 1、切换对应目录&#xff0c;更新器默认目录是 C:\Qt 2、文件名镜像源 安装示例&#xff1a; .\qt-unified-windows-x…

包管理器npm, cnpm, yarn 和 pnpm 的命令

npm (Node Package Manager) 安装与更新 npm install 或 npm i&#xff1a; 安装项目依赖&#xff1a;根据 package.json 文件安装所有列出的依赖。参数&#xff1a; -S, --save&#xff1a;保存到 dependencies&#xff08;默认行为&#xff09;。-D, --save-dev&#xff1a;…

python中权重剪枝,低秩分解,量化技术 代码

目录 python中权重剪枝,低秩分解,量化技术 代码 权重剪枝 低秩分解 scipy 量化技术 python中权重剪枝,低秩分解,量化技术 代码 权重剪枝 权重剪枝可以通过PyTorch的torch.nn.utils.prune模块实现。以下是一个简单的例子: import torch import torch.nn as nn impor…