【java基础】Stream流的各种操作

文章目录

  • 基本介绍
  • 流的创建
  • 流的各种常见操作
    • forEach方法
    • filter方法
    • map方法
    • peek方法
    • flatMap方法
    • limit和skip方法
    • distinct方法
    • sorted方法
  • 收集结果
    • 收集为数组(toArray)
    • 收集为集合(collect)
    • 收集为Map
  • 关于流的一些说明(终结操作)
  • 总结

基本介绍

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

与集合相比,流提供了一种可以让我们在更高概念级别上指定计算任务的数据视图

注意:学习Stream必须要十分清晰的了解lamdba表达式,如果lambda不清楚,请参考一篇文章彻底搞懂lambda表达式


流的创建

我们在学习流之前,应当先了解一下Stream这个类,Stream类的类图和方法如下

在这里插入图片描述
在这里插入图片描述

对于创建流,我们可以使用静态方法Stream.of来创建

在这里插入图片描述

该方法传入一个可变长度的参数,然后就会返回对应类型的流

        Stream<Integer> stream = Stream.of(2, 3, 1, 4);

如果要创建一个不包含任何元素的流,可以使用Stream.empty

        Stream<Object> empty = Stream.empty();

我们还可以使用Stream的静态方法generate和iterate来创建无限流。

下面就通过generate创建了一个获取随机数的流

在这里插入图片描述

        Stream<Double> randomNumStream = Stream.generate(Math::random);

如果想要创建例如0,1,2,3这样有规律的序列流,那么就可以使用iterate方法

在这里插入图片描述

        Stream<Integer> iterate = Stream.iterate(0, num -> num+1);

除了上面几个静态方法,对于流的创建还有许多方法,例如Arrays.stream方法

在这里插入图片描述

在Collection中有stream方法和parallelStream方法都可以返回一个Stream流,这也就说明了所有的集合都可以调用这2个方法返回对应的流

在这里插入图片描述

对于流,我们有几点注意事项如下

  • 流并不存储元素,这些元素可能存储在底层的集合中,或者是按需生成的
  • 流的操作不会改变其数据源
  • 流的操作尽可能惰性执行。这意味着直至需要其结果时,操作才会执行

流的各种常见操作

这里主要介绍在流里面使用频率较高的几个操作,每个方法都会给出该方法的源注释,以及基本使用,请参考注释和代码来进行理解


forEach方法

这个方法可以对流里面的每一个元素执行操作

在这里插入图片描述

        Stream<Integer> stream = Stream.of(2, 3, 1, 4);
        stream.forEach(System.out::println);

输出结果如下

2
3
4
1

filter方法

该方法可以过滤掉流中不满足要求的元素,会返回一个新流

在这里插入图片描述

        Stream<Integer> stream = Stream.of(2, 3, 1, 4);
        Stream<Integer> newStream = stream.filter(num -> num > 2);
        System.out.print("过滤之后:");
        newStream.forEach(x -> System.out.print(x + " "));

上面代码输出如下

过滤之后:3 4 

map方法

当我们想要按照某种方式来转换流中的值的时候,我们就可以使用map

在这里插入图片描述

        Stream<Integer> stream = Stream.of(2, 3, 1, 4);
        Stream<Integer> newStream = stream.map(num -> num + 1);
        newStream.forEach(System.out::println);

上面代码输出如下

3
4
2
5

peek方法

该方法可以对流中的每一个元素进行操作,返回新的流

在这里插入图片描述

public class Dog {
    public String name;
    public Integer age;

    public Dog(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
        Dog[] dogs = {new Dog("tom", 1),new Dog("旺财", 2)};
        Stream<Dog> dogStream = Arrays.stream(dogs);
        Stream<Dog> newDogStream = dogStream.peek(dog -> dog.age = 999);
        newDogStream.forEach(System.out::println);

上面代码输出如下

Dog{name='tom', age=999}
Dog{name='旺财', age=999}

flatMap方法

该方法产生一个流,它是通过将传入lambda表达式应用于当前流中所有元素所产生的结果连接到一起而获得的。(注意,这里的每个结果都是一个流。)

在这里插入图片描述

        List<Stream<Integer>> streamList = new ArrayList<>();
        Stream<Integer> stream1 = Stream.of(1, 2, 3);
        Stream<Integer> stream2 = Stream.of(4, 5, 6);
        Stream<Integer> stream3 = Stream.of(7, 8, 9);
        streamList.add(stream1);
        streamList.add(stream2);
        streamList.add(stream3);

        Stream<Stream<Integer>> stream = streamList.stream();
        // flatMap里面的lambda表达式应当返回一个流
        Stream<Integer> integerStream = stream.flatMap(x -> x);
        integerStream.forEach(System.out::println);

上面代码输出如下

1
2
3
4
5
6
7
8
9

limit和skip方法

limit方法可以对流进行裁剪,只取前n个流,skip方法则是跳过前n个流

在这里插入图片描述
在这里插入图片描述

由于limit和skip用法基本由于,这里就用limit作为例子

        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
        Stream<Integer> newStream = stream.limit(4);
        newStream.forEach(System.out::println);

上面代码输出如下

1
2
3
4

distinct方法

这个方法相当于去重

在这里插入图片描述

        Stream<Integer> stream = Stream.of(1, 2, 3, 3, 1, 4);
        Stream<Integer> newStream = stream.distinct();
        newStream.forEach(System.out::println);

代码输出如下

1
2
3
4

sorted方法

这个方法一看就知道是排序用的

在这里插入图片描述

该方法有2个,一个带有Comparator,就是用于指定排序方式的

        Stream<Integer> stream = Stream.of(4, 1, 3, 2);
        Stream<Integer> newStream = stream.sorted();
        newStream.forEach(System.out::println);

代码输出如下

1
2
3
4

收集结果

在上面我们都只是对流进行操作,现在来讲解下如何将流里面的数据收集到集合中。


收集为数组(toArray)

我们可以调用流里面的toArray方法,传入对应的类型数组即可
在这里插入图片描述

        Stream<String> namesStream = Stream.of("tom", "luck", "jerry");
        String[] names = namesStream.toArray(String[]::new);
        System.out.println(Arrays.toString(names));

上面代码输出如下

[tom, luck, jerry]

收集为集合(collect)

调用stream里面的collect方法,然后传入指定的Collector实例即可,Collector提供了大量用于生成常见收集器的工厂方法。

Collector类的方法如下

在这里插入图片描述
在这里插入图片描述

可以发现有很多方法,这里先介绍几个常用的,其他的方法在后面文章中进行说明。

        List<Integer> nums = Arrays.asList(1,2,3,1,4);

toList()可以将结果收集为List

        List<Integer> list = nums.stream().collect(Collectors.toList());

toSet()可以将结果收集为Set

        Set<Integer> set = nums.stream().collect(Collectors.toSet());

toCollection()可以指定收集的集的种类

        TreeSet<Integer> treeSet = nums.stream().collect(Collectors.toCollection(TreeSet::new));

在Collector这个类里面还有其他的很多方法,建议大家去看看这个类的文档,对每个方法都有个影响,需要用到某种操作的时候查找文档即可。


收集为Map

Map也是集合,但是Map收集要比如List,Set等要麻烦一点,所以这里单独说明一下,toMap方法如下

在这里插入图片描述

我们需要指定k和v是什么,其实就是对于每一个元素,用什么来作为k和v

        Stream<String> namesStream = Stream.of("tom", "jack", "lucy");
        Map<Character, String> namesMap = namesStream
                .collect(Collectors
                        .toMap(k -> k.charAt(0), v -> v.toUpperCase()));
        System.out.println(namesMap);

上面代码就用字符串的第一个字符作为k,然后用字符串的大写作为v。上面代码输出如下

{t=TOM, j=JACK, l=LUCY}

使用toMap还有一点需要说明,就是key不能冲突,看下面代码,就会产生key冲突

        Stream<String> namesStream = Stream.of("tom", "jack", "lucy","ttpfx");
        Map<Character, String> namesMap = namesStream
                .collect(Collectors
                        .toMap(k -> k.charAt(0), v -> v.toUpperCase()));
        System.out.println(namesMap);

如果产生key冲突,那么collect方法会抛出一个一个IllegalStateException异常

在这里插入图片描述

对于key冲突的情况,我们应该给出解决key冲突的逻辑,toMap还有一个重载的方法,用于解决key冲突。也就是保留新值还是旧值

在这里插入图片描述

我们遇到key冲突旧保存最新的值即可

        Stream<String> namesStream = Stream.of("tom", "jack", "lucy", "ttpfx");
        Map<Character, String> namesMap = namesStream
                .collect(Collectors
                        .toMap(k -> k.charAt(0),
                                v -> v.toUpperCase(),
                                (oldV, newV) -> newV));
        System.out.println(namesMap);

上面代码输出如下

{t=TTPFX, j=JACK, l=LUCY}

对于toMap,都有一个等价的toConcurrentMap


关于流的一些说明(终结操作)

我们先来看下面代码

        Stream<Integer> stream = Stream.of(2, 3, 1, 4);
        stream.forEach(System.out::println);
        Stream<Integer> newStream = stream.filter(x -> x > 2);
        newStream.forEach(System.out::println);

上面代码逻辑很简单,就是先输出流里面的元素,然后过滤一下,最后再输出。按理说这个代码应该是没有问题的,我们运行一下

在这里插入图片描述

可以发现报错了,报错的原因就是说流已经关闭了,很奇怪啊,我们明明没有执行close操作

造成流关闭的原因就是 forEach方法。还记得在文章开始的说明吗?流是惰性执行的,在流执行终止操作前,流其实都没有执行。而forEach就是一个终止操作。对于终结方法,我们可以简单理解为就是返回值不是Stream的方法。

我们用代码验证一下Stream的惰性执行

        List<Integer> list = new ArrayList<>();
        list.add(1);
        Stream<Integer> stream = list.stream();
        list.add(2);
        long count = stream.count();
        System.out.println(count);

大家想一下,count是多少?由于Stream是惰性执行的,那么count显然应该就是2
在这里插入图片描述


总结

在这篇文章中介绍了Stream的一些基本使用,对于Stream还有许多的方法没有说明,这些会在后面的文章中进行说明。Stream里面还有一个很重要的Optional,这个将在下一篇文章中进行说明。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WEB网站服务(一)

1.1 Apache网站服务基础1.1.1Apache简介Apache HTTP Server是开源软件项目的杰出代表&#xff0c;基于标准的HTTP网络协议提供网页浏览服务。Apache服务器可以运行在Linux,UNIX&#xff0c;windows等多种操作系统平台中。1.Apache的起源1995年&#xff0c;Apache服务程序的1.0版…

Linux- 系统随你玩之--玩出花活的命令浏览器-双生姐妹花

文章目录1、背景2、命令浏览器-双生姐妹花2.1、姐妹花简介2.2 、验名正身2.3、常用功能选项3、常用实操3.1、发送请求获取文件3.1.1、抓取页面内容到一个文件中3.1.2、多个文件下载3.1.3、下载ftp文件3.1.4、断点续传3.1.5、上传文件3.1.6、内容输出3.2 、利用curl测试接口3.3 …

毕业设计 基于51单片机自动智能浇花系统设计

基于51单片机自动智能浇花系统设计1、毕业设计选题原则说明&#xff08;重点&#xff09;2、项目资料2.1 系统框架2.2 系统功能3、部分电路设计3.1 STC89C52单片机最小系统电路设计3.2 按键电路设计3.3 水泵控制电路设计4、部分代码展示4.1 数码管位选程序4.2 ad0832数据读取程…

HTTPS协议,看这篇就够了

不安全的HTTP 近些年来&#xff0c;越来越多的网站使用 HTTPS 协议进行数据传输&#xff0c;原因在于 HTTPS 相较于 HTTP 能够提供更加安全的服务。 很多浏览器对于使用 HTTP 协议的网站会加上『警告』的标志表示数据传输不安全&#xff0c;而对于使用 HTTPS 协议的网站会加上…

C++11智能指针

目录 一、智能指针的初步认识 1.1 使用场景 1.2 原理 二、std::auto_ptr 2.1 管理权转移 2.2 auto_ptr的模拟实现 三、std::unique_ptr 四、std::shared_ptr 4.1 基础设计 4.2 线程安全问题 4.3 定制删除器 五、std::weak_ptr 六、C11与Boost中智能指针的关系 一、…

脱不下孔乙己的长衫,现代的年轻人该怎么办?

“如果我没读过书&#xff0c;我还可以做别的工作&#xff0c;可我偏偏读过书” “学历本该是我的敲门砖&#xff0c;却成了我脱不下的长衫。” 最近&#xff0c;“脱下孔乙己的长衫”在网上火了。在鲁迅的原著小说中&#xff0c;孔乙己属于知识阶级&#xff08;长衫客&#xf…

网络安全工具大合集

还是一句话&#xff0c;功夫再高&#xff0c;也怕菜刀首先&#xff0c;恭喜你发现了宝藏。本文章集成了全网优秀的开源攻防武器项目&#xff0c;包含&#xff1a;信息收集工具&#xff08;自动化利用工具、资产发现工具、目录扫描工具、子域名收集工具、指纹识别工具、端口扫描…

Json数据传递参数

文章目录Json数据传递参数集合参数&#xff1a;Json格式POJO参数&#xff1a;json格式集合参数&#xff1a;json格式RequestBody与RequestParam的区别时间参数的转换Json数据传递参数 第一步 在pom文件中添加相关配置第二步 作用时开启json数据转换成对象postman发送json数据…

CSS 实现六边形柱状图

前言 &#x1f44f;CSS 实现六边形柱状图 速速来Get吧~ &#x1f947;文末分享源代码。记得点赞关注收藏&#xff01; 1.实现效果 2.实现步骤 定义全局css变量&#xff0c;柱状宽度为–w&#xff0c;最大高度为–h&#xff0c;柱形整体为渐变色&#xff0c;定义上部分颜色为…

【STL三】序列容器——array容器

【STL三】序列容器——array一、array简介二、头文件三、模板类四、成员函数1、迭代器2、元素访问3、容量4、操作五、demo1、容量&#xff08;不使用迭代器&#xff09;2、使用迭代器3、元素访问 at()、front()、back()、data()一、array简介 array 容器是 C 11 标准中新增的序…

ChatGPT能否取代程序员?

目录ChatGPT能否取代程序员&#xff1f;ChatGPT和程序员的工作内容和工作方式ChatGPT和程序员的共同点程序员的优势程序员的实力ChatGPT和程序员的关系结论惊喜ChatGPT能否取代程序员&#xff1f; ChatGPT是一种非常普遍的人工智能&#xff08;AI&#xff09;系统&#xff0c;…

基于springboot家政服务管理系统(程序+数据库+文档)

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

基于java+SpringBoot+Vue的论坛管理系统设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】

博主介绍&#xff1a;专注于Java技术领域和毕业项目实战 &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案例&#xff08;200套&#xff09; 目录 一、效果演示 二、…

MyBatis --- 缓存、逆向工程、分页插件

一、MyBatis的缓存 1.1、MyBatis的一级缓存 一级缓存是SqlSession级别的&#xff0c;通过同一个SqlSession查询的数据会被缓存&#xff0c;下次查询相同的数据&#xff0c;就会从缓存中直接获取&#xff0c;不会从数据库重新访问 使一级缓存失效的四种情况&#xff1a; 1、…

Python生日蛋糕

目录 前言 底盘 蛋糕 蜡烛 祝福 前言 Hello&#xff0c;小伙伴们晚上好吖&#xff01;前两天博主满20岁啦&#xff08;要开始奔三辽呜呜呜&#xff09;&#xff0c;这几天收到了不少小伙伴们的祝福&#xff0c;浪漫的小博主想送给大家一份不一样的生日蛋糕&#xff0c…

【Linux】学会这些基本指令来上手Linux吧

前言上篇文章介绍了一些常用的指令&#xff0c;这篇文章再来介绍一下Linux必须学会的指令。一.时间相关的指令ate显示date 指定格式显示时间&#xff1a; date %Y:%m:%d date 用法&#xff1a;date [OPTION]... [FORMAT]1.在显示方面&#xff0c;使用者可以设定欲显示的格式&am…

2023最全最牛的Jmeter接口测试教程及接口测试详情,你不知道的东西太多了!

下边是详细的jmeter接口测试入门到精通的详细教程&#xff0c;还有视频版本教您实战操作&#xff01; 2023年B站最新Jmeter接口测试实战教程&#xff0c;精通接口自动化测试只需要这一套视频_哔哩哔哩_bilibili2023年B站最新Jmeter接口测试实战教程&#xff0c;精通接口自动化…

算法套路四——反转链表

算法套路四——反转链表 算法示例一&#xff1a;LeetCode206. 反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 初始化pre为空&#xff0c;cur为头指针 pre指针&#xff1a;记录当前结点的前一个结点 cur指针&#xff1a;记录当…

SpringBoot整合MongoDB

参考链接 https://www.mongodb.org.cn/ 文章目录一、前言1.1 NoSQL介绍1.1.1 NoSQL 数据库分类1.1.2 NoSQL的优点/缺点1.1.3 BASE1.2 MongoDB介绍1.2.1 MongoDB和SQL对比1.2.2 数据库1.2.3 元数据1.2.4 MongoDB 数据类型二、SpringBoot整合MongDB2.1 环境配置2.2 MongoTemplate…

XCPC第十一站,带你学会图论基本算法

我们约定&#xff1a;以下n表示点的数目&#xff0c;m表示边的数目。 引子1——邻接表存储图的方法&#xff08;&#xff09;&#xff08;暂时不考虑重边和自环&#xff09; 现在我们有n个点&#xff08;编号为1~n&#xff09;和m条边&#xff0c;要用数组存储它们&#xff0c…