【Java】流式编程学习笔记

news2024/11/23 9:10:59

文章目录

  • 一、流简介
  • 二、创建流
    • 2.1 由值创建流:of
    • 2.2 由列表创建流:stream
    • 2.3 由 Builder 创建流:build
    • 2.4 由文件生成流:lines
    • 2.5 由函数生成流
      • 2.5.1 迭代(如果不做限制,就是创建无限流):iterate
      • 2.5.2 生成:generate
  • 三、常用操作
    • 3.1 筛选
      • 3.1.1 filter
      • 3.1.2 limit
    • 3.2 映射
      • 3.2.1 map
    • 3.3 查找和匹配
      • 3.3.1 anyMatch
      • 3.3.2 allMatch
      • 3.3.3 findAny
      • 3.3.4 findFirst
    • 3.4 规约
      • 3.4.1 reduce
        • 3.4.1.1 元素求和
        • 3.4.1.2 最大值
        • 3.4.1.3 最小值
    • 3.5 数值流
      • 3.5.1 对象流映射到数值流
        • 3.5.1.1 mapToInt
        • 3.5.1.2 mapToDouble
        • 3.5.1.3 mapToLong
      • 3.5.2 数值流转换回对象流
        • 3.5.2.1 boxed
      • 3.5.3 数值流的应用


一、流简介

  • 流式 API 从 Java8 开始引入,支持链式书写。
  • 流在管道中流通,在节点被处理。
  • Stream是独特的,既不同于io,也不同于List。
  • Stream在理论上能容纳无限对象,List不能
  • 流不是一种数据结构,流存储的只是一种数据视图。
  • 流的计算是惰性计算,真正的计算通常只发生在最后的结果获取时。流式计算存在第一步、中间一步、最后一步的说法,只有当到达最后一步执行函数的时候,整个惰性函数才会执行。
  • 流只能消费一次,不能被两次消费

如下的代码,对stream进行了两次遍历,所以会报错

List<String> stringList = Arrays.asList("Java", "Python", "C++", "Matlab");
        Stream<String> stream = stringList.stream();
        stream.forEach(System.out::println);
        stream.forEach(System.out::println);

在这里插入图片描述


二、创建流

2.1 由值创建流:of

方法一:使用静态方法 Stream.of() ,通过显式值创建一个流

        Stream<String> stream = Stream.of("Java","Python","C++","Matlab");
        String[] arr = new String[]{"Java","Python","C++","Matlab"};
        Stream<String> stream = Stream.of(arr);

2.2 由列表创建流:stream

方法二:使用 Collection 的 stream() 方法,创建一个流

        List<String> list = Arrays.asList("Java","Python","C++","Matlab");
        Stream<String> stream = list.stream();

2.3 由 Builder 创建流:build

方法三:使用 builder() 创建一个流

        Stream<String> stream = Stream.<String>builder()
                .add("Java")
                .add("Python")
                .add("C++")
                .add("Matlab")
                .build();

2.4 由文件生成流:lines

方法四:使用 Files.lines() 创建一个流

        Stream<String> stream = null;
        try {
            stream = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
        }catch (IOException e){
            e.printStackTrace();
        }

2.5 由函数生成流

2.5.1 迭代(如果不做限制,就是创建无限流):iterate

        Stream<Integer> stream = Stream.iterate(0, n -> n + 2)
                .limit(10);
        stream.forEach(System.out::println); // 0,2,4,6,8,10,12,14,16,18

下面用迭代的方法生成斐波那契数列:

        Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]})
                .limit(10)
                .forEach(t -> {
                    System.out.println(t[0] + " " + t[1]);
                });

输出如下:

0 1
1 1
1 2
2 3
3 5
5 8
8 13
13 21
21 34
34 55

2.5.2 生成:generate

下面是生成 4 个随机数的代码

        // 0.24958123386777675,0.3934127178560789,0.45154850021573034,0.005268717434774417,
        Stream.generate(Math::random)
                .limit(4)
                .forEach(num -> System.out.print(num + ",")); 

三、常用操作

这是下面例子中会用到的学生对象,下面会利用流式编程,对学生列表进行一系列操作

    static class Student{
        String name;
        int age;
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

下面是获取学生列表的函数,后面都会以这个学生列表进行举例说明

    public static List<Student> createStudentList(){
        return Arrays.asList(
                new Student("WSKH",21),
                new Student("WRQ",22),
                new Student("SXC",20),
                new Student("XCY",36),
                new Student("CZG",40),
                new Student("LHH",18)
        );
    }

在后面,假设我们已经通过上面的函数获取到了学生列表,并将其命名为 studentList

List<Student> studentList = createStudentList();

3.1 筛选

3.1.1 filter

filter():返回一个包括所有符合谓词的元素的流

应用实例:获取年龄在 25 以下的学生

        List<Student> result = studentList.stream().filter(student -> {
            return student.age < 25;
        }).collect(Collectors.toList());

3.1.2 limit

limit(n):该方法会返回一个不超过给定长度的流

应用实例:获取年龄在25以下的学生,并且要求结果中的学生不超过2位

        List<Student> result = studentList.stream().filter(student -> {
            return student.age < 25;
        }).limit(2).collect(Collectors.toList());

3.2 映射

3.2.1 map

map():对流中每一个元素应用函数

应用案例:获取所有学生的年龄

        List<Integer> result = studentList.stream().map(student -> {
            return student.age;
        }).collect(Collectors.toList());

应用案例:获取所有学生的名字

        List<String> result = studentList.stream().map(student -> {
            return student.name;
        }).collect(Collectors.toList());

3.3 查找和匹配

3.3.1 anyMatch

anyMatch():判断流中是否有一个元素能匹配给定的谓词

应用案例:判断是否有小于等于18岁的学生

        boolean b = studentList.stream().anyMatch(student -> student.age <= 18);

3.3.2 allMatch

allMatch():判断流中的元素是否都能匹配给定的谓词

应用案例:判断是否所有的学生都大于18岁

        boolean b = studentList.stream().allMatch(student -> student.age > 18);

3.3.3 findAny

findAny():返回当前流中的任意元素

应用案例:获取任意一个大于25岁的学生

        Optional<Student> any = studentList.stream().filter(student -> {
            return student.age > 25;
        }).findAny();
        System.out.println(any); // Optional[Student{name='XCY', age=36}]

3.3.4 findFirst

findFirst():返回当前流中的第一个元素

应用案例:获取学生列表中第一个大于25岁的学生

        Optional<Student> first = studentList.stream().filter(student -> {
            return student.age > 25;
        }).findFirst();
        System.out.println(first); // Optional[Student{name='XCY', age=36}]

3.4 规约

3.4.1 reduce

reduce(p1,p2):操作组合流中的所有元素以产生单个值。
reduce的第一个参数:初始值,相当于给求和或者求最大最小值一个初值
reduce的第二个参数:一个BinaryOperator来将两个元素结合起来产生一个新值

3.4.1.1 元素求和

应用案例:求出学生们的年龄总和

        int sum = studentList.stream().map(student -> {
            return student.age;
        }).reduce(0, (a, b) -> a + b);
        System.out.println(sum); // 157

也可以简写如下,用 Integer::sum 简化 (a, b) -> a + b

        int sum = studentList.stream().map(student -> {
            return student.age;
        }).reduce(0, Integer::sum);
        System.out.println(sum); // 157

3.4.1.2 最大值

应用案例:求出学生们的最大年龄

        int maxAge = studentList.stream().map(student -> {
            return student.age;
        }).reduce(0, (a, b) -> a > b ? a : b);
        System.out.println(maxAge); // 40

3.4.1.3 最小值

应用案例:求出学生们的最小年龄

        int minAge = studentList.stream().map(student -> {
            return student.age;
        }).reduce(Integer.MAX_VALUE, (a, b) -> a < b ? a : b);
        System.out.println(minAge); // 18

3.5 数值流

在Java中,因为Java泛型不支持基本类型,所以我们无法使用像Stream这样的形式来保存int,只能采用形如Integer这样的形式。但是频繁装箱、拆箱操作会牺牲编译器的大量性能。

​ 所以为了提高效率,Java标准库提供了三种使用基本类型的Stream,它们的使用和标准的Stream没有太大区别,直接使用:

  • IntStream
  • LongStream
  • DoubleStream

他们也被称为数值流。

3.5.1 对象流映射到数值流

3.5.1.1 mapToInt

mapToInt():返回一个 IntStream(而不是一个Stream)

        IntStream intStream = studentList.stream().mapToInt(student -> student.age);

3.5.1.2 mapToDouble

mapToDouble():返回一个 DoubleStream(而不是一个Stream)

        DoubleStream doubleStream = studentList.stream().mapToDouble(student -> student.age);

3.5.1.3 mapToLong

mapToLong():返回一个 LongStream(而不是一个Stream)

        LongStream longStream = studentList.stream().mapToLong(student -> student.age);

3.5.2 数值流转换回对象流

3.5.2.1 boxed

boxed():要把原始流转换成一般流(这里每个int都会装箱成一个Integer)

        IntStream intStream = studentList.stream().mapToInt(student -> student.age);
        Stream<Integer> boxed = intStream.boxed();

3.5.3 数值流的应用

应用案例:求出学生们的年龄总和

        int sum = studentList.stream().mapToInt(student -> student.age).sum();
        System.out.println(sum); // 157

应用案例:求出学生们的最大年龄

        OptionalInt max = studentList.stream().mapToInt(student -> student.age).max();
        System.out.println(max.isPresent() ? max.getAsInt() : "不存在最大值"); // 40

应用案例:求出学生们的最小年龄

        OptionalInt min = studentList.stream().mapToInt(student -> student.age).min();
        System.out.println(min.isPresent() ? min.getAsInt() : "不存在最小值"); // 18

应用案例:求出学生们的平均年龄

        OptionalDouble average = studentList.stream().mapToInt(student -> student.age).average();
        System.out.println(average.isPresent() ? average.getAsDouble() : "不存在平均值"); // 26.166666666666668

应用案例:求出大于25岁的学生的数量

        long count = studentList.stream().mapToInt(student -> student.age).filter(age -> {
            return age > 25;
        }).count();
        System.out.println(count); // 2

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

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

相关文章

线性结构之单链表详解

文章目录前言一.单链表的结构体二、单链表的基本接口1.SListMalloc&#xff08;申请节点&#xff09;2.SListPushBack&#xff08;尾插&#xff09;3.SListPushFront&#xff08;头插&#xff09;4.SListPopBack&#xff08;尾删&#xff09;5.SListPopFront&#xff08;头删&a…

0115 作用域,对象

作用域意义&#xff1a;一段代码中所用到的名字不总是有效可用的&#xff0c;限定这个名字的可用性代码范围全局作用域全局有效&#xff0c;作用所有代码局部作用域局部有效&#xff0c;作用于函数内的代码环境&#xff0c;和函数有关也称函数作用域块级作用域在大括号{}有效&a…

Docker中安装Centos

window版的docker 1.cmd拉取centos镜像 docker pull centos2.启动centos容器&#xff0c;并把docker上centos的22端口映射到本机50001端口(端口号可以自己指定) 3.进入到Centos容器 通过docker命令,查看当前存在的镜像或者容器 查看镜像: docker images查看容器: docker …

js如何实现随机数切换

前言在一些电商网站,或一些活动页上,看到一些特效,比如:抽奖时,点击图片,实现图片的随机切换,数字的随机切换等,为了吸引用户的注意力,增加网页的互动性,这个效果是怎么实现的呢01具体示例https://coder.itclan.cn/fontend/js/14-click-num-suiji/点击文末左下角阅读原文,即可查…

MySQL三大日志(binlog、redo log和undo log)详解

MySQL三大日志binlog、redo log和undo log详解1.redo logredo log概述刷盘时机innodb_flush_log_at_trx_commit0innodb_flush_log_at_trx_commit1innodb_flush_log_at_trx_commit2日志文件组2.binlogbinlog 概述记录格式写入机制刷盘时机3.两阶段提交4.undo log5.总结1.redo lo…

SSL和TLS协议如何提供身份验证、机密性和完整性

SSL 和 TLS 协议使两方能够相互识别和验证&#xff0c;并以机密性和数据完整性进行通信。SSL 和 TLS 协议通过 Internet 提供通信安全性&#xff0c;并允许客户端/服务器应用程序以保密和可靠的方式进行通信。这些协议有两层&#xff1a;记录协议和握手协议&#xff0c;它们位于…

要命!我篡改了系统命令惊现事故,竟要扣我年终奖-Golang-cobra

打工还是要打工的。。我最后也没发出去。 紧急处理以后&#xff0c;现在写复盘&#xff0c;大家随我看看我到底是在学习哪些内容。 &#xff08;以上内容纯属虚构&#xff0c;如有雷同纯属巧合&#xff09; 简介 之前我们讲过pflag和os.Args&#xff0c;现在说说cobra这个命令行…

如何将SQL Server数据从表导出到CSV文件

在本文中,我们将使用四种不同的工具将表从SQL Server导出到.csv文件。此外,你将学习如何将带有或不带有头的SQL查询结果导出到.csv文件。 SQL Server数据从表导出到CSV文件 使用SQL Server Management Studio将SQL结果导出到具有或不具有标题的CSV文件一、不带标题二、带标题…

图形编辑器:图形和辅助线绘制的坐标问题

大家好&#xff0c;我是前端西瓜哥。今天看看绘制图形和辅助线时&#xff0c;坐标转换的一些注意点。 项目地址&#xff0c;欢迎 star&#xff1a; https://github.com/F-star/suika 线上体验&#xff1a; https://blog.fstars.wang/app/suika/ 先回顾一下之前讲的视口坐标和场…

docker镜像与容器实践

一、引子 镜像和容器是不同的概念&#xff0c;本文主要是为了通过实践来强化对这两种不同概念的理解。 二、安装docker 安装docker&#xff0c;执行以下命令即可&#xff1a; # 安装依赖 yum install -y yum-utils device-mapper-persistent-data lvm2 # 设置国内源 yum-co…

显示Linux系统上的服务

init 和 systemd 都是 Linux的 init 守护进程&#xff0c;systemd出现较晚&#xff0c;最近的 Linux 发行版中很常用。init 使用service命令管理服务&#xff0c;而Systemd用systemctl命令管理服务。init 和 systemd 都是 Linux的 init 守护进程&#xff0c;即使你的 Linux 系统…

Maven3.8.*系列 settings.xml详解

文章目录文末,拿完整Settings配置文件设置参考介绍简要概述设置详细信息简单的价值观插件组服务器密码加密的镜像代理配置文件激活性能库插件的储存库活动概况直达文末,拿完整Settings配置文件结语文末,拿完整Settings配置文件 设置参考 介绍 简要概述 的 settings 元素 set…

返乡上云图

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

PicGo+Github搭建图床

文章目录一、Github仓库创建二、配置PicGo三、实际体验四、PicGo 2.3.1参考资料一、Github仓库创建 PS&#xff1a;它只会显示一次&#xff0c;所以最好把它复制下来到你的备忘录存好&#xff0c;方便下次使用&#xff0c;否则下次有需要重新新建&#xff1b; 二、配置PicGo …

Linux进程控制(进程退出+进程等待)

目录 一、子进程创建 1.1 fork函数深入 1.2 写时拷贝 二、进程退出 2.1.1 进程退出码概念 2.1.2 系统退出码文字描述 2.1.3 _exit和exit函数 2.1.4 查看退出码 三、进程等待 3.1 进程等待解决僵尸进程 3.2 进程等待方法 3.2.1 wait 3.2.2 waitpid(&#xff09; 四、…

seata部署指南(v1.6.1)

Seata 搭建 db模式版本 V1.6.1一、 简介二、下载三、建表&#xff08;仅db&#xff09;四、配置 seata server 参数4.1、V1.4.2之前方式4.2、V1.4.2 之后推荐方式(seataServer.properties)五、配置Server5.1、 修改 appplication.yml5.1.1、 修改 appplication.yml seata.store…

文件操作(File类)

文章目录一、初识文件二、File类构造方法常用方法一、初识文件 我们目前是如何存储数据的?弊端是什么? int a 1; int[] arr new int[5];我们这些数据是在内存中存储的&#xff0c;是不能够长久保存的。 那么&#xff0c;我们的计算机当中有没有一块硬件可以长久存储数据…

PostgreSQL(一)Windows安装

目录一、下载二、安装PostgreSQL三、安装StackBuilder四、打开PostgreSQL管理工具pgAdmin五、打开命令行一、下载 下载地址&#xff1a; https://www.enterprisedb.com/downloads/postgres-postgresql-downloads 下载后安装包如下&#xff1a; 二、安装PostgreSQL 双击打开安…

DataX使用入门

DataX 是阿里云 DataWorks数据集成 的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS)、Hologres、DRDS 等各种异构数据…

Java 日志框架 Log4J

文章目录引言什么是Log4JLog4J三大组件Log4J日志级别Log4J基本使用自定义配置文件Appender示例FileAppenderDailyRollingFileAppenderRollingFileAppenderJDBCAppender自定义Logger引言 Java 日志框架 JUL 在这篇文章中已经向大家介绍了我们为什么要使用日志文件、常见的日志…