探索 Java 8 中的 Stream 流:构建流的多种方式

在这里插入图片描述
人嘛,要懂得避嫌…

开篇引入

Java 8引入了Stream流作为一项新的特性,它是用来处理集合数据的一种函数式编程方式。Stream流提供了一种更简洁、高效和易于理解的方法来操作集合数据,同时也能够实现并行处理,以提高性能。

以下是Stream流的一些重要特征和用法:

  1. 流的创建:可以从集合、数组、I/O通道等多种数据源创建Stream流。例如,使用Collection.stream()方法可以将集合转换为流,使用Arrays.stream()可以将数组转换为流。

  2. 中间操作:Stream流支持各种中间操作,这些操作允许对流中的元素进行过滤、映射、排序等操作,而不会修改原始数据。一些常见的中间操作包括filter(过滤元素)、map(映射元素)、sorted(排序元素)等。

  3. 终端操作:终端操作是对流进行最终操作,它们触发实际的计算并生成结果。一些常见的终端操作包括forEach(遍历元素并执行操作)、collect(将流中的元素收集到一个集合中)、count(计算元素个数)等。

  4. 延迟执行:Stream操作是延迟执行的,这意味着中间操作可以在不实际计算的情况下链接在一起。只有在调用终端操作时,才会触发流的处理。

  5. 并行处理:Stream流支持并行处理,通过使用parallelStream()方法,可以轻松地将流的处理分布到多个处理器核心上,以提高性能。

  6. 函数式编程风格:Stream流鼓励使用函数式编程风格,其中操作是以lambda表达式的形式传递的,使代码更具表达力和简洁。

以下是一个示例,演示了如何使用Stream流来操作一个集合:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);int sum = numbers.stream().filter(n -> n % 2 == 0) // 过滤偶数.map(n -> n * 2) // 将偶数翻倍.reduce(0, Integer::sum); // 求和System.out.println("偶数的翻倍之和为: " + sum);

这只是Stream流的一个简单示例,它展示了Stream流的一些常见操作,如过滤、映射和汇总。通过Stream流,可以以更简洁和可读的方式处理集合数据,减少了样板代码,提高了代码质量和可维护性。下面我们将对构建流的多种方式多种方式展开做一个详细阐述。

1.从集合创建流

从集合创建Stream流非常简单,可以使用集合类的stream()方法来获取一个Stream对象。下面我将展示如何从集合创建Stream,并结合实际应用提供两个代码示例。

示例1:从List创建Stream

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;public class StreamCreationExample {public static void main(String[] args) {List<String> names = new ArrayList<>();names.add("Alice");names.add("Bob");names.add("Charlie");names.add("David");names.add("Eve");// 创建一个Stream流Stream<String> nameStream = names.stream();// 使用Stream流进行操作nameStream.filter(name -> name.startsWith("A")).forEach(System.out::println);}
}

这个示例中,我们首先创建了一个包含一些姓名的List集合,然后使用names.stream()方法创建了一个Stream流。接着,我们使用filter中间操作筛选出以"A"开头的姓名,并使用forEach终端操作打印输出结果。

示例2:从Map创建Stream

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;public class StreamCreationFromMapExample {public static void main(String[] args) {Map<Integer, String> studentMap = new HashMap<>();studentMap.put(1, "Alice");studentMap.put(2, "Bob");studentMap.put(3, "Charlie");studentMap.put(4, "David");studentMap.put(5, "Eve");// 从Map的键集合创建StreamStream<Integer> studentIdsStream = studentMap.keySet().stream();// 使用Stream流进行操作studentIdsStream.filter(id -> id % 2 == 0).forEach(id -> System.out.println(id + ": " + studentMap.get(id)));}
}

这个示例中,我们创建了一个包含学生ID和姓名的Map,然后使用studentMap.keySet().stream()方法从Map的键集合创建了一个Stream流。接着,我们使用filter中间操作筛选出偶数的学生ID,并使用forEach终端操作打印出相应的学生信息。

2.从数组创建流

从数组创建Stream流也非常简单,Java 8 提供了Arrays.stream() 方法,它允许将一个数组转换为一个Stream流。下面我将详细介绍如何从数组创建Stream,并提供两个代码示例。

示例1:从整数数组创建Stream

import java.util.Arrays;
import java.util.stream.IntStream;public class StreamCreationFromArrayExample {public static void main(String[] args) {int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// 从整数数组创建IntStreamIntStream numberStream = Arrays.stream(numbers);// 使用Stream流进行操作int sum = numberStream.filter(n -> n % 2 == 0).map(n -> n * 2).sum();System.out.println("偶数的翻倍之和为: " + sum);}
}

在这个示例中,我们首先创建了一个整数数组 numbers,然后使用 Arrays.stream(numbers) 方法将它转换为一个 IntStream 流。接着,我们使用该流进行一系列操作,包括筛选出偶数并将其翻倍,最后计算它们的总和。

示例2:从字符串数组创建Stream

import java.util.Arrays;
import java.util.stream.Stream;public class StreamCreationFromArrayExample {public static void main(String[] args) {String[] words = {"apple", "banana", "cherry", "date", "elderberry"};// 从字符串数组创建StreamStream<String> wordStream = Arrays.stream(words);// 使用Stream流进行操作wordStream.filter(word -> word.startsWith("b")).map(String::toUpperCase).forEach(System.out::println);}
}

在这个示例中,我们创建了一个字符串数组 words,然后使用 Arrays.stream(words) 方法将它转换为一个 Stream 流。接着,我们使用流进行操作,包括筛选出以字母 “b” 开头的单词,并将它们转换为大写形式后打印输出。

3.静态工厂方法

Java 8也引入了一些静态工厂方法来创建Stream流,这些方法使得创建Stream流变得更加简便和灵活。下面我将详细介绍这些静态工厂方法,并提供两个代码示例。

静态工厂方法创建Stream

  1. Stream.of(T... values):通过将一个可变参数的元素列表传递给Stream.of方法来创建一个包含这些元素的Stream流。这对于创建具有少量元素的流非常方便。

  2. Stream.empty():使用Stream.empty()方法创建一个空的Stream流。

  3. Stream.generate(Supplier<T> s):通过提供一个Supplier函数来创建一个无限大小的Stream流,该函数会生成元素。通常,需要使用limit操作限制生成的元素数量。

  4. Stream.iterate(T seed, UnaryOperator<T> f):通过提供初始值(seed)和一个一元操作函数(UnaryOperator)来创建一个包含无限序列的Stream流。例如,可以使用Stream.iterate(0, n -> n + 1)来创建一个自然数序列的Stream流。

示例1:使用Stream.of创建Stream

import java.util.stream.Stream;public class StreamFactoryExample {public static void main(String[] args) {// 使用Stream.of创建Stream流Stream<String> stream = Stream.of("Apple", "Banana", "Cherry", "Date");// 打印Stream中的元素stream.forEach(System.out::println);}
}

这个示例使用Stream.of静态工厂方法创建了一个包含水果名称的Stream流,并使用forEach终端操作打印出每个水果的名称。

示例2:使用Stream.generate创建Stream

import java.util.Random;
import java.util.stream.Stream;public class StreamGenerateExample {public static void main(String[] args) {// 使用Stream.generate创建随机整数流Stream<Integer> randomIntStream = Stream.generate(() -> new Random().nextInt(100));// 限制流的元素数量,然后打印randomIntStream.limit(10).forEach(System.out::println);}
}

在这个示例中,我们使用Stream.generate静态工厂方法创建了一个包含随机整数的Stream流。然后,我们使用limit操作限制了流中元素的数量,最后打印出了生成的随机整数。

这些静态工厂方法为创建不同类型的Stream提供了便捷的途径,使流的创建更加灵活和便捷。

4.使用 Stream.Builder

Stream.Builder是Java 8引入的用于构建流的一种方式。它允许逐个添加元素到流中,并最终构建一个Stream对象。这对于在迭代或生成元素的过程中构建流非常有用。

下面是如何使用Stream.Builder创建流的详细介绍,并提供两个代码示例。

使用Stream.Builder创建流的步骤:

  1. 创建Stream.Builder对象:首先,需要创建一个Stream.Builder对象。

  2. 添加元素:然后,使用Stream.Builderadd方法逐个添加元素到流中。

  3. 构建流:一旦添加了所有元素,可以调用Stream.Builderbuild方法来构建Stream对象。

示例1:使用Stream.Builder创建流并过滤奇数

import java.util.stream.Stream;public class StreamBuilderExample {public static void main(String[] args) {Stream.Builder<Integer> builder = Stream.builder();// 添加元素到Streamfor (int i = 1; i <= 10; i++) {builder.accept(i);}// 构建StreamStream<Integer> numberStream = builder.build();// 使用Stream操作numberStream.filter(n -> n % 2 == 0) // 过滤偶数.forEach(System.out::println);}
}

在这个示例中,我们首先创建了一个Stream.Builder对象,然后使用accept方法逐个添加1到10的整数到流中,最后使用filter中间操作筛选出偶数并使用forEach终端操作打印出结果。

示例2:使用Stream.Builder生成斐波那契数列

import java.util.stream.Stream;public class FibonacciStreamExample {public static void main(String[] args) {Stream.Builder<Long> builder = Stream.builder();long a = 0, b = 1;int count = 10;for (int i = 0; i < count; i++) {builder.accept(a);long next = a + b;a = b;b = next;}Stream<Long> fibonacciStream = builder.build();fibonacciStream.forEach(System.out::println);}
}

在这个示例中,我们使用Stream.Builder生成斐波那契数列的前10个数字。我们首先创建一个Stream.Builder对象,然后使用循环逐个添加斐波那契数列的元素,最后使用forEach终端操作打印出结果。

Stream.Builder适用于需要逐个生成元素并构建流的情况,使代码更加清晰和灵活。

5. 从文件创建流

在Java中,可以从文件创建Stream流以便进行文件的读取和处理。通常,可以使用java.nio.file包中的类来实现这一目的。以下是如何从文件创建流的方法以及两个代码示例:

方法1:使用Files.lines方法创建文本文件的流

Files.lines方法允许创建一个包含文件内容的Stream<String>,适用于文本文件的逐行读取。该方法接受文件路径作为参数,并返回一个Stream对象。

下面是一个示例:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;public class FileToStreamExample {public static void main(String[] args) {String filePath = "sample.txt"; // 文件路径try (Stream<String> lines = Files.lines(Paths.get(filePath))) {lines.forEach(System.out::println); // 逐行打印文件内容} catch (IOException e) {e.printStackTrace();}}
}

在这个示例中,我们使用Files.lines方法打开名为"sample.txt"的文本文件,并将其内容逐行打印到控制台。

方法2:使用Files.newInputStream方法创建二进制文件的流

如果要处理二进制文件,例如图像或音频文件,可以使用Files.newInputStream方法创建一个InputStream,然后将其转换为Stream。下面是一个示例:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;public class BinaryFileToStreamExample {public static void main(String[] args) {String filePath = "image.jpg"; // 二进制文件路径try {Path path = Paths.get(filePath);Stream<Byte> byteStream = Files.newInputStream(path).map(b -> (byte) b);byteStream.forEach(System.out::println); // 逐字节打印二进制文件内容} catch (IOException e) {e.printStackTrace();}}
}

在这个示例中,我们使用Files.newInputStream方法创建一个输入流,然后将其映射为Stream<Byte>,并最终逐字节打印二进制文件的内容。

无论是文本文件还是二进制文件,从文件创建Stream流都是非常有用的,它使文件的读取和处理变得更加方便和灵活。在处理文件时,不要忘记适当地处理可能出现的IOException异常。

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

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

相关文章

Cesium:CGCS2000坐标系的xyz坐标转换成WGS84坐标系的经纬高度,再转换到笛卡尔坐标系的xyz坐标

作者:CSDN @ _乐多_ 本文将介绍使用 Vue 、cesium、proj4 框架,实现将CGCS2000坐标系的xyz坐标转换成WGS84坐标系的经纬高度,再将WGS84坐标系的经纬高度转换到笛卡尔坐标系的xyz坐标的代码。并将输入和输出使用 Vue 前端框架展示了出来。代码即插即用。 网页效果如下图所示…

VueX中的getters配置项

一、配置getters属性 当我们想对VueX中的state中的数据进行处理&#xff0c;我们就可以使用getter配置项。 就像是组件中的数据和计算属性之间的关系。 const getters { 属性名 (state) { return 处理结果; } } 我们能够直接拿到state进行操作&#xff0c;并返回操作结果。 …

Shadingsphere proxy 启动报错 Windows

Exception in thread "main" java.lang.NoClassDefFoundError 本来打算在本地电脑测试一下proxy的功能&#xff0c;使用的二进制安装包&#xff0c;没想到怎么都启动不起来&#xff0c;一直报找不到某个类的错误。我还以为是自身的配置有问题&#xff0c;等我copy了…

梯度消失和梯度爆炸的原因

梯度消失和梯度爆炸 梯度爆炸和梯度消失本质上是因为梯度反向传播中的连乘效应。 梯度下降算法 举一个简单的例子,函数表达式为loss 2w^2 4w,如下图 ​​​​​​​ ​​​​​​​ 为了求得w的最优值,使得loss最小,从上图很容易看出来当w -1时,loss最小…

服务器数据恢复—EMC存储pool上数据卷被误删的数据恢复案例

服务器数据恢复环境&#xff1a; EMC Unity某型号存储&#xff0c;连接了2台硬盘柜。2台硬盘柜上创建2组互相独立的POOL&#xff0c;2组POOL共有21块520字节硬盘。21块硬盘组建了2组RAID6&#xff0c;1号RAID6有11块硬盘. 2号RAID6有10块硬盘。 服务器故障&检测&#xff1…

【MySQL】 索引(上)

文章目录 1. 索引的概念2. MySQL与磁盘 的交互基本单位3. 建立共识4. 现象与结论如何理解mysql中page概念为什么 要采用page的方案 进行交互 而不是用多少加载多少&#xff1f; 5. 页目录为什么要引入 页目录概念单页情况多页情况使用B树 构建索引为什么不用其他数据结构为什么…

Classifier-Free Guidance

1.为什么需要分类引导 顾名思义&#xff0c;在原来扩散模型的基础上加上一个引导&#xff0c;让扩散模型朝着我们想要的方向去生成图像 从上图可以了解到生成下一张图像是有分类器参与的 无分类器就是这种形式要参与下一张图像的生成

SQL server数据库端口访问法

最近数据库连接&#xff0c;也是无意中发现了这个问题&#xff0c;数据库可根据端口来连接 网址:yii666.com< 我用的是sql2014测试的&#xff0c;在安装其他程序是默认安装了sql(sql的tcp/ip端口为xxx)&#xff0c;服务也不相同&#xff0c;但是由于比较不全&#xff0c;我…

ElementUI 自定义 Tree 树形控件背景

在 template 中 <div class"container"><el-tree :data"treeList" :props"defaultProps" accordion node-click"handleNodeClick" /> </div> 在 script 中 treeList: [{ id: "-1", label: "区域选…

oracle (8)Managing Tablespace Data File

目录 一、基础知识 1、表空间和数据文件 2、存储层次结构摘要 3、表空间的类型 4、表空间中的空间管理 5、临时表空间 6、Default Temporary TS 默认临时TS 二、常用实操 1、Creating Tablespaces创建表空间 2、Dictionary-Managed TS 字典管理的表空间 3、Locally …

uniapp 关于 video 组件的缩放比例问题

在 container 样式的 padding-bottom 设置比例值 9/16 比例值&#xff1a;56.25% 3/4 比例值&#xff1a;75% <view class"container"><video class"video-box" src"xxx.mp4" /> </view> .container {position: relative;wid…

与AI对话的艺术:如何优化Prompt以获得更好的响应反馈

前言 在当今数字化时代&#xff0c;人工智能系统已经成为我们生活的一部分。我们可以在智能助手、聊天机器人、搜索引擎等各种场合与AI进行对话。然而&#xff0c;要获得有益的回应&#xff0c;我们需要学会与AI进行有效的沟通&#xff0c;这就涉及到如何编写好的Prompt。 与…

设计模式之观察者模式

文章目录 一、介绍二、实现思路三、基本角色四、案例1. 不使用观察者模式2. 使用观察者模式 五、java中的观察者模式六、spring中的观察者模式七、优缺点 一、介绍 观察者模式(Observer Pattern)&#xff0c;又称监听器模式(Listener Pattern) 或 发布-订阅模式(Publish-Subsc…

OpenFeign的简单介绍和功能实操

前言 本文主要做一下OpenFeign的简单介绍和功能实操&#xff0c;实操主要是OpenFeign的超时和重试&#xff0c;在阅读本文章前&#xff0c;请完成《Nacos 注册中心介绍与实操》内的Nacos多模块生产消费者项目 什么是OpenFeign OpenFeign全名Spring Cloud OpenFeign&#xff…

树结构及其算法-二叉查找树

目录 树结构及其算法-二叉查找树 C代码 树结构及其算法-二叉查找树 二叉树在建立的过程中是根据“左子树 < 树根 < 右子树”的原则建立的&#xff0c;因此只需从树根出发比较键值即可&#xff0c;如果比树根大就往右&#xff0c;否则往左而下&#xff0c;直到相等就找…

基于OR-Tools的装箱问题模型求解(PythonAPI)

装箱问题 一、背包问题&#xff08;Knapsack problem&#xff09;1.1 0-1背包模型基于OR-Tools的0-1背包问题求解&#xff08;PythonAPI&#xff09;导入pywraplp库数据准备声明MIP求解器初始化决策变量初始化约束条件目标函数调用求解器打印结果 1.2 多重背包问题&#xff08;…

diffusers-Load pipelines,models,and schedulers

https://huggingface.co/docs/diffusers/using-diffusers/loadinghttps://huggingface.co/docs/diffusers/using-diffusers/loading 有一种简便的方法用于推理是至关重要的。扩散系统通常由多个组件组成&#xff0c;如parameterized model、tokenizers和schedulers&#xff0c…

SpringBoot整合自签名SSL证书,转变HTTPS安全访问(单向认证服务端)

前言 HTTP 具有相当优秀和方便的一面,然而 HTTP 并非只有好的一面&#xff0c;事物皆具两面性&#xff0c;它也是有不足之处的。例如&#xff1a; 通信使用明文&#xff08;不加密&#xff09;&#xff0c;内容可能会被窃听。不验证通信方的身份&#xff0c;因此有可能会遭遇…

多线程锁的升级原理是什么

在 Java 中&#xff0c;锁共有 4 种状态&#xff0c;级别从低到高依次为&#xff1a;无状态锁&#xff0c;偏向锁&#xff0c;轻量级锁和重量级锁状态&#xff0c;这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级。 多线程锁锁升级过程 如下图所示 多线程锁的升级过程…

Ha-NeRF源码解读 train_mask_grid_sample

目录 背景&#xff1a; &#xff08;1&#xff09;Ha_NeRF论文解读 &#xff08;2&#xff09;Ha_NeRF源码复现 &#xff08;3&#xff09;train_mask_grid_sample.py 运行 train_mask_grid_sample.py解读 1 NeRFSystem 模块 2 forward()详解 3 模型训练tranining_st…