java中stream常用api介绍

stream相关api对于集合操作非常方便,可以通过链式编程完成数据的处理,有时候很复杂的数据处理通过使用stream的相关api可以非常方便的完成,使用lambda表达式更可以简化为一行代码,下面就介绍一下stream的相关api方法,感受一下如何使用。

一、构建stream操作流

构建stream流的方式有很多种,比较常见的两种方式:
一是通过集合的 .stream() 构建流或 .parallelStream() 构建并行流;二是通过Stream类的相关api构建流。

  1. 通过集合的stream()或parallelStream()方法构建:
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
Set<Integer> set = new HashSet<>(list);// 构建普通流
Stream<Integer> stream1 = list.stream();
Stream<Integer> stream2 = set.stream();// 构建并行流
Stream<Integer> pstream1 = list.parallelStream();
Stream<Integer> pstream2 = set.parallelStream();

这里的并行流要注意,它默认使用的是系统中的 ForkJoinPool.commonPool 线程池,这个线程池默认大小是CPU核数,如果要调整线程池大小,可以有两种方法调整系统变量:

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "4");
或
-Djava.util.concurrent.ForkJoinPool.common.parallelism=4

添加一个打印逻辑验证处理线程名:

pstream1.forEach(item -> System.out.println(Thread.currentThread().getName() + " : " + item));

没有添加上面的参数打印输出内容是:

main : 7
main : 6
ForkJoinPool.commonPool-worker-18 : 2
ForkJoinPool.commonPool-worker-4 : 1
ForkJoinPool.commonPool-worker-18 : 10
main : 9
ForkJoinPool.commonPool-worker-4 : 4
ForkJoinPool.commonPool-worker-25 : 3
ForkJoinPool.commonPool-worker-11 : 8
ForkJoinPool.commonPool-worker-29 : 5

添加配置后的输出内容:

main : 7
main : 6
ForkJoinPool.commonPool-worker-1 : 3
ForkJoinPool.commonPool-worker-1 : 5
ForkJoinPool.commonPool-worker-2 : 9
ForkJoinPool.commonPool-worker-3 : 2
ForkJoinPool.commonPool-worker-1 : 4
ForkJoinPool.commonPool-worker-3 : 1
ForkJoinPool.commonPool-worker-0 : 8
ForkJoinPool.commonPool-worker-2 : 10

可见配置参数确实调整了系统线程池的大小,由于主线程也会参与计算,所以对于计算密集型的服务,线程池一般设置为CPU核数 - 1。

  1. 通过Stream的api构建
    通过stream的api构建,主要是Stream.of()方法构建:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
stream.forEach(System.out::println);

对于特定类型的stream还有专门的api构建,比如IntStream的range()和rangeClosed()方法构建一个范围内的数据,其中range()方法包含开始数据不包含结束数据,rangeClosed()方法包含开始数据同时包含结束数据。

// 包括开始不包括结束
System.out.println("----------------stream1----------------");
IntStream stream1 = IntStream.range(1, 10);
stream1.forEach(System.out::println);// 包括开始和结束
System.out.println("----------------stream2----------------");
IntStream stream2 = IntStream.rangeClosed(1, 10);
stream2.forEach(System.out::println);
  1. 通过Arrays的stream()方法构建:
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IntStream stream = Arrays.stream(arr);
stream.forEach(System.out::println);

上面就是几种常用的构建stream流方式,使用stream流主要是处理数据,处理数据又分为中间方法和终结方法,它们的主要区别就是中间方法处理完后还可以继续使用stream流进行接下来的处理;而终结方法执行后的流不能继续使用,要想继续使用就必须重新开启一个流再次执行。
下面所有的流使用的都是这个stream做演示:

List<Integer> list = new ArrayList<>(Arrays.asList(3, 6, 10, 5, 5, 2, 6, 4, 9, 7, 8, 1, 8, 9));
Stream<Integer> stream = list.stream();
二、中间方法

中间方法执行后获取到的仍然是一个可以使用的流,常用的中间方法如下:

  1. 过滤数据filter()
// 筛选大于3且小于8的数据
stream.filter(new Predicate<Integer>() {@Overridepublic boolean test(Integer i) {return i > 3 && i < 8;}
}).forEach(item -> System.out.println(item));// lambda表达式
stream.filter(i -> i > 3 && i < 8).forEach(System.out::println);
  1. 选择一个区间的数据:skip()是跳过的数据条数,limit()是返回的数据条数
// 跳过前2条数据返回5条数据
stream.skip(2).limit(5).forEach(System.out::println);
  1. 数据去重distinct()
stream.distinct().forEach(System.out::println);
  1. 数据排序sorted()
// 默认排序是升序排列
stream.sorted().forEach(System.out::println);// 自定义排序:降序排列
stream.sorted(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1 > o2 ? -1 : (o1.intValue() == o2.intValue() ? 0 : 1);}
}).forEach(item -> System.out.println(item));// lambda表达式
stream.sorted((o1, o2) -> o1 > o2 ? -1 : (o1.intValue() == o2.intValue() ? 0 : 1)).forEach(System.out::println);
  1. 修改数据类型map()
stream.map(new Function<Integer, String>() {@Overridepublic String apply(Integer i) {return "i-" + i;}
}).forEach(item -> System.out.println(item));// lambda表达式
stream.map(i -> "i-" + i).forEach(System.out::println);
  1. 修改数据类型flatMap()
stream.flatMap((Function<Integer, Stream<?>>) num -> {// 因式分解该整数if(num <= 2) {return Stream.of(num);}List<Integer> nums = new ArrayList<>();int i = num;while (i >= 2) {for(int j = 2; j <= i; j++) {if(i % j == 0) {nums.add(j);i /= j;break;}}}return nums.stream();
}).forEach(System.out::println);

注意:map()和flatMap()这两个方法都能实现改变数据类型,主要区别是map()方法修改类型后返回的是单个元素、flatMap()方法修改类型后返回的是一个stream流,主要用于修改类型后返回的是一个集合的场景。
7. 获取数据peek()方法
在数据流处理过程中,我们想查看一下当前数据的内容或记录数据信息到日志中,可以通过peek()方法执行,该方法只是对数据查看而不会改变数据的内容:

// 打印数据
stream.peek(System.out::println).forEach(System.out::println);

peek()方法与forEach()方法的区别是:peek()输出数据后不影响流的继续操作;而forEach()方法输出数据后流不能继续执行。peek()方法执行虽然不能修改元素,但是可以修改元素内属性的值而对流的执行不产生影响。

@Data
@Builder
public class DemoVo {private int id;private String name;
}List<DemoVo> list = Arrays.asList(DemoVo.builder().build(), DemoVo.builder().build(), DemoVo.builder().build());
// 通过peek()方法设置对象的属性值
list.stream().peek(System.out::println).peek(c -> c.setName("name")).forEach(System.out::println);
三、终结方法

终结方法执行完后,这个流不能继续执行,常见的终结方法有下面这些:

  1. max()、min()、count()三个取值方法
// 最大值
Integer max = stream.max(Comparator.comparingInt(o -> o)).get();
System.out.println(max);// 最小值
Integer min = stream.min(Comparator.comparingInt(o -> o)).get();
System.out.println(min);// 计数
long count = stream.count();
System.out.println(count);
  1. forEach() 遍历流中的数据
stream.forEach(System.out::println);
  1. toArray()方法将流转换为数组
Integer[] arr = stream.toArray(new IntFunction<Integer[]>() {@Overridepublic Integer[] apply(int value) {return new Integer[value];}
});// lambda表达式
Integer[] arr = stream.toArray(value -> new Integer[value]);
System.out.println(Arrays.toString(arr));
  1. collect()将流收集到指定类型集合中
// 收集到list
List<Integer> list = stream.collect(Collectors.toList());// 收集到set
Set<Integer> set = stream.collect(Collectors.toSet());// 收集到map:两个函数分别用于键的生成规则和值的生成规则,要注意键不能重复,否则会抛出异常
Map<Integer, String> map = stream.collect(Collectors.toMap(new Function<Integer, Integer>() {@Overridepublic Integer apply(Integer i) {return i;}
}, new Function<Integer, String>() {@Overridepublic String apply(Integer i) {return "val-" + i;}
}));// lambda表达式
Map<Integer, String> map = stream.collect(Collectors.toMap(i -> i, i -> "val-" + i));

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

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

相关文章

Latex学习

二 实例 1. \Delta_{w}\frac{\partial l}{\partial w_{i1}}weight:\frac{\partial l}{\partial x_{i1}} 效果如下 其中对于希腊字母的大小写来说&#xff0c;可以参考&#xff1a; 【LaTeX 语法】字母表示 ( 大写、小写、异体 希腊字母 | 粗体字母 | 花体字母 )_latex字母_韩…

Centos8部署LNMP架构

LNMP架构 LNMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写。L指Linux&#xff0c;N指Nginx&#xff0c;M一般指MySQL&#xff0c;也可以指MariaDB&#xff0c;P一般指PHP&#xff0c;也可以指Perl或Python。 1.Linux是一类Unix计算机操作系统的统称…

09【保姆级】-GO语言的数组和切片

09【保姆级】-GO语言的数组 一、数组1.1 数组定义1.2 数组的使用1.3 数组的遍历1.4 数组的应用案例 二、切片2.1 切片的介绍2.2 切片的原理2.3 切片的三种使用 之前我学过C、Java、Python语言时总结的经验&#xff1a; 先建立整体框架&#xff0c;然后再去抠细节。先Know how&a…

Spring框架学习 -- 创建与使用

目录 (1) 创建spring 项目 ① 创建maven项目 ②添加spring框架支持 ③ 添加启动项 (2) 创建 Bean对象 (3) 将Bean注入到容器 (4) 获取Bean对象 (5) 注意事项 (6) Spring的创建和使用流程图 创作不易多多支持 (1) 创建spring 项目 首先我们使用的开发工具为idea 专业版…

为什么原生IP可以降低Google play账号关联风险?企业号解决8.3/10.3账号关联问题?

在Google paly应用上架的过程中&#xff0c;相信大多数开发者都遇到过开发者账号因为关联问题&#xff0c;导致应用包被拒审和封号的情况。 而众所周知&#xff0c;开发者账号注册或登录的IP地址及设备是造成账号关联的重要因素之一。酷鸟云最新上线的原生IP能有效降低账号因I…

时间序列预测(9) — Informer源码详解与运行

目录 1 源码解析 1.1 文件结构 1.2 mian_informer.py文件 1.3 模型训练 1.4 模型测试 1.5 模型预测 2 Informer模型 2.1 process_one_batch 2.2 Informer函数 2.3 DataEmbedding函数 2.4 ProbAttention稀疏注意力机制 2.5 Encoder编码器函数 2.6 Decoder解码器函数…

PG数据中DBeaver上传csv文件作为数据表

DBeaver 是一个开源的数据库工具&#xff0c;还是蛮好用的&#xff0c;有时候需要我们上传数据做表&#xff0c;数据为CSV格式的&#xff0c;DBeaver本身自带有功能实现的。 可打开连着的数据库&#xff0c;找到模式&#xff0c;点到下面的表里&#xff0c;选择一个表直接导入…

【Linux系统化学习】进程优先级 | 进程饥饿 | 进程切换

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统化学习 目录 进程优先级 什么是优先级&#xff1f; 为什么会有优先级&#xff1f; 如何做到的&#xff1f; 优先级的动态调整 查看进程优先级的命令 PRI 和 NI PRI VS NI 修改进程优先级 …

关于sh脚本文件

.sh文件是一种脚本文件&#xff0c;主要用于在Unix或Linux系统中运行shell命令。与其他文件格式的主要区别在于&#xff0c;.sh文件可以被操作系统的shell程序&#xff08;如bash、sh、zsh等&#xff09;直接执行。这使得.sh文件非常适合用于自动化任务&#xff0c;例如设置环境…

SpringBoot集成jjwt和使用

1.引入jwt依赖&#xff08;这里以jjwt为例&#xff0c;具体其他jwt产品可以参见jwt官网&#xff09; <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version> </dependency>…

FreeRTOS内存管理分析

目录 heap_1.c内存管理算法 heap_2.c内存管理算法 heap_3.c内存管理算法 heap_4.c内存管理算法 heap_5.c内存管理算法 内存管理对应用程序和操作系统来说非常重要&#xff0c;而内存对于嵌入式系统来说是寸土寸金的资源&#xff0c;FreeRTOS操作系统将内核与内存管理分开实…

Redis:新的3种数据类型Bitmaps、HyperLoglog、Geographic

目录 Bitmaps简介常用命令bitmaps与set比较 HyperLoglog简介命令 Geographic简介命令 Bitmaps 简介 位操作字符串。 现代计算机使用二进制&#xff08;位&#xff09;作为信息的基本单位&#xff0c;1个字节等于8位&#xff0c;例如“abc”字符串是有3个字节组成&#xff0c…

Parallel Diffusion Models of Operator and Image for Blind Inverse Problems

盲逆问题算子和图像的并行扩散模型 论文链接&#xff1a;https://arxiv.org/abs/2211.10656 项目链接&#xff1a;https://github.com/BlindDPS/blind-dps Abstract 在正向算子已知的情况下(即非盲)&#xff0c;基于扩散模型的逆问题求解器已经展示了最先进的性能。然而&…

css鼠标横向滚动并且不展示滚动条几种方法

需求&#xff1a;实现内容超出之后使用属性滚轮进行左右查看超出内容&#xff0c;并且隐藏滚动条 1.不使用框架实现 每次滚动就滚动40px的距离 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name&quo…

STM32——STM32Cubemx的学习使用总结

文章目录 一、简介二、STM32Cube IDE与MX区别&#xff1f;三、界面介绍和使用四、使用整体框架 一、简介 STM32CubeMX是一个图形化工具&#xff0c;可以非常容易地配置STM32微控制器和微处理器&#xff0c;以及为ArmCortex-M 内核或部分 Linux 设备树生成相应的初始化C代码&…

编译器优化代码研究

《Effective C》条款21&#xff1a; /** * 结论&#xff1a;对自定义类型对象表达式objA*objB objC; * 定义friend MyInt operator*(const MyInt& lhs,const MyInt& rhs) * 编译器优化后&#xff1a;operator*()函数内直接在调用接收处构造(此处的匿名临时对象)&am…

wireshark 过滤设置

gpt: Wireshark 是一个网络分析工具&#xff0c;可以用来捕获和分析网络数据包。你可以使用过滤器来筛选并查看你感兴趣的数据包。Wireshark 使用的是基于BPF&#xff08;Berkeley Packet Filter&#xff09;语法的过滤器。以下是一些常见的 Wireshark 过滤器设置&#xff1a;…

CANopen权威指南【CAN总线协议】

1这个总线定义是老外发明的。 想要使用&#xff0c;就必须按照协议去配置数据帧。 CIA301和cia402协议&#xff0c;实际就是寄存器地址上某一段的定义。 下载地址&#xff1a; CAN in Automation (CiA): Technical documents 注册下载也是非常快的。【没什么难度】 就是资…

HTTP响应详解

HTTP响应格式 HTTP响应报文通常由四个部分组成: 响应行(Response Line):包含协议版本、状态码和状态消息,例如:HTTP/1.1 200 OK。 响应头(Response Headers):包含了一系列的键值对,用来描述关于响应的信息,比如内容类型、日期、服务器信息等等。 空行:即CRLF(回车…

栈:C++实现

引言&#xff1a; 在C中实现栈是一种常见的数据结构操作。栈是一种后进先出&#xff08;LIFO&#xff09;的数据结构&#xff0c;它具有push&#xff08;压栈&#xff09;、pop&#xff08;出栈&#xff09;、getTop&#xff08;获取栈顶元素&#xff09;和isEmpty&#xff08;…