【学习笔记】Java函数式编程03 Stream流-终结操作

news2024/11/20 13:32:41

书接上回

3.3.3 终结操作

3.3.3.1 forEach

对集合的每一个元素进行处理

接触很多了不赘述

3.3.3.2 count

用来获取当前流中的元素的个数

比如,打印出所有作家的作品的总数

System.out.println(authors.stream()
                   .flatMap(author -> author.getBooks().stream())
                   .count());
3.3.3.3 max和min

可以用来流中的最值。

查看源码可以发现这个方法是需要传入参数的

Optional<T> max(Comparator<? super T> comparator);
Optional<T> min(Comparator<? super T> comparator);

Comparator是一个比较器,但是这里的比较器是什么作用呢?其实stream流的球最值和前面的sorted的实现逻辑类似,都是要求先比较排序后再求最值

另外,这个方法的返回值是Optional类型,这个类型后续会再细讲。

所以max和min不用死记,学会sorted就可以满足需要了

3.3.3.4 ⭐️collect

将流当中的元素转换为一个集合(List/Set/Map)。

阅读源码可以发现collect的两个参数都非常复杂,在实际使用中会使用工具类的方法来快速实现

image-20231212172433634

小练习快速上手

1、获取一个所有作者名字的集合List

authors.stream()
    .map(Author::getName)
    .collect(Collectors.toList())

2、获取一个所有书名的集合SET

authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .map(Book::getName)
    .collect(Collectors.toSet());

顺带一提,由于set的去重作用,所有其实前面提到的“去重“的需求,也可以尝试用collect来实现

3、获取一个map集合,Key为作者名,Value为作品集List

沿用前面的思路,利用Collectors.toMap方法实现,但是转map是需要指定key和v的,研究toMap方法就可以发现:这里确实要求传入两个Function函数式接口,如下

image-20231221102613795

尝试先写一个匿名内部类的原生写法,然后进行简化:

// 获取一个map集合,Key为作者名,Value为作品集List
List<Author> authors = Author.getAuthor(5);
Map<String, List<Book>> map = authors.stream()
        .collect(Collectors.toMap(new Function<Author, String>() {
            @Override
            public String apply(Author author) {
                return author.getName();
            }
        }, new Function<Author, List<Book>>() {
            @Override
            public List<Book> apply(Author author) {
                return author.getBooks();
            }
        }));

System.out.println(map);

// 第一次简化
authors.stream()
    .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));

// IDEA提供的进一步简化
authors.stream()
    .collect(Collectors.toMap(Author::getName, Author::getBooks));

不难发现,toMap方法就是分别指定key和value就可以实现转map的要求了

4、获取一个map集合,Key为作者名,Value为作者

注意:需求不同,这次是将val作为作者本身的对象,这个其实也是比较常见的需求

Map<String, List<Author>> collect = author.stream()
    .collect(Collectors.groupingBy(new Function<Author, String>() {
        @Override
        public String apply(Author author) {
            return author.getName();
        }
    }));

// 简化后
author.stream().collect(Collectors.groupingBy(Author::getName));

介绍完简单的终结操作后,接下来还有一些比较复杂的操作。比如需求场景

  • 判断是否有25岁以上的作家?
  • 判断是不是所有作家都刚满18岁?

3.3.4 终结操作之查找与匹配

3.3.4.1 anyMatch

任一元素符合条件,则返回true

3.3.4.2 allMatch

所有符合条件,则返回true

3.3.4.3 nonMatch

所有的元素都不符合条件

(这个不需要硬记,和allMatch互为补集)


3.3.4.4 findAny

image-20231221112305126

这个操作用于获取流中的任意一个元素,注意,这个操作无法保证获取的是第一个元素

3.3.4.5 findFirst

这个操作用于获取流中的第一个元素。

  • 这个终结操作一般需要结合limitsorted使用

补充说明

这两个方法返回的对象是JDK8新增的Optional对象,用于避免空指针等异常的,后续会详细介绍。

  • 要获取里面的对象使用get()方法即可。
  • ifPresent()方法可以在对象存在时,执行方法内的函数

3.3.5 ⭐️终结操作之归并操作-reduce

reduce单词字面意思有减少的意思,可以引申为缩小、裁剪的意思

image-20231226144739020

3.3.5.1 reduce概念

对流中的数据,按照指定的计算方式,计算出一个结果。(缩紧操作)

reduce的作用,将stream中的元素“组合”起来,最终传出组合的结果,起到一个紧缩、简化的作用。

两种实现方式

  • 传入一个初始值,按照给定的计算方式以此与流中的每个元素进行“计算”,每次计算得到的结果都可以和后面的元素再进行计算,并最终给出结果。
  • 没有初始值,而是将第一个元素给定为初始值,然后以此和流内的其他元素进行“计算”并给出结果。

两种方式对应reduce的两种重写方式

  • T reduce(T identity, BinaryOperator<T> accumulator);
  • Optional<T> reduce(BinaryOperator<T> accumulator);
3.3.5.2 reduce有初始值的重写

T reduce(T identity, BinaryOperator<T> accumulator);

查看源码注释可以发现,双参数的实现逻辑如下:

T result = identity;  
for (T element : this stream)      
    result = accumulator.apply(result, element)  
    return result;

做两个求最值的快速练习——求出所有作家的最大年纪

List<Author> authors = Author.getAuthor();
// 先打印出每个作家的年纪
authors.stream()
    .map(Author::getAge)
    .sorted()
    .forEach(System.out::println);
System.out.println("-----------------");
// 求最大值 匿名内部类写法
Integer max = authors.stream()
    .map(Author::getAge)
    .reduce(Integer.MIN_VALUE, new BinaryOperator<Integer>() {
        @Override
        public Integer apply(Integer element, Integer next) {
            return element < next ? next : element;
        }
    });
System.out.println(max);
// 求最大值 lambda简化
Integer max1 = authors.stream()
    .map(Author::getAge)
    .reduce(Integer.MIN_VALUE, (element, next) -> element < next ? next : element);
System.out.println(max1);

顺带一提前面学到的max()和min()底层就是使用reduce实现的

3.3.5.3 reduce无初始值的调用

Optional<T> reduce(BinaryOperator<T> accumulator);

实现低层逻辑是这样的:

boolean foundAny = false;  
T result = null;  
for (T element : this stream) {      
    if (!foundAny) {          
        foundAny = true;         
        result = element;      
    }     
    else          
        result = accumulator.apply(result, element);  
}  
return foundAny ? Optional.of(result) : Optional.empty();

逻辑就是:

  • 第一个元素给定为初始值,然后以此和流内的其他元素进行“计算”并给出结果。
  • 由于如果流为空返回的对象可能为空,所有这里使用了Optional进行包装

做个练习,一样是求最大年纪

// 匿名内部类原生写法
Optional<Integer> optional = authors.stream()
    .map(Author::getAge)
    .reduce(new BinaryOperator<Integer>() {
        @Override
        public Integer apply(Integer element, Integer next) {
            return element < next ? next : element;
        }
    });
//  lambda简化
Optional<Integer> optional1 = authors.stream()
    .map(Author::getAge)
    .reduce((element, next) -> element < next ? next : element);
optional.ifPresent(System.out::println);
optional1.ifPresent(System.out::println);

3.4 Stream流的注意事项

  • 惰性求值
  • 一次性流
  • 不会影响原数据

3.4.1 惰性求值

没有任何终结操作,前面的中间操作都不会得到执行和保留。

  • 实际开发过程中,由于没有终结操作的stream写法并不会编译报错
  • 所以在写代码的时候一定要养成添加终结操作的习惯)

3.4.2 流是一次性的

在进行终结操作后,流会失效(报废。

举个例子:

在这里插入图片描述

  • 在实际开发过程中,使用stream流应该在调用stream()方法后就使用链式编程直到终结操作
  • 如果需要再次操作,就重新调用并生成新的流即可

3.4.3 不会影响原数据

特指是正常操作,而且这也是选择stream流所期望的。

举个例子,在map操作中将年龄+10,其实集合中元素的年龄是不会变化的。

image-20231226161532252

  • 在实际开发中,如果是需要对集合的元素进行操作时,则不建议使用stream流
  • 使用了stream流也应该尽量避免对集合中的元素进行操作(增删改)

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

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

相关文章

第九部分 图论

目录 例 相关概念 握手定理 例1 图的度数列 例 无向图的连通性 无向图的连通度 例2 例3 有向图D如图所示&#xff0c;求 A, A2, A3, A4&#xff0c;并回答诸问题&#xff1a; 中间有几章这里没有写&#xff0c;感兴趣可以自己去学&#xff0c;组合数学跟高中差不多&#xff0c…

2024,华为重塑笔记本的“创新周期”

作者 | 曾响铃 文 | 响铃说 谈及电脑PC&#xff0c;相信不少消费者都会下意识地给行业贴一个标签&#xff1a;夕阳行业。毕竟当下已经是移动互联网时代&#xff0c;传统PC的使用场景不断萎缩&#xff0c;市场研究机构Gartner报告显示&#xff0c;截至2023年第三季度&#xff…

LLM应用于MPC

现有的基于学习的自动驾驶系统&#xff08;AD&#xff09;在理解高级信息和提供可解释性方面存在挑战。为了解决这些问题&#xff0c;这项工作采用LLM作为复杂AD场景的决策组件。作者设计了认知途径&#xff08;cognitive pathway&#xff09;来实现LLM的综合推理&#xff0c;并…

python作业题百度网盘,python作业答案怎么查

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python作业题百度网盘&#xff0c;python作业答案怎么查&#xff0c;今天让我们一起来看看吧&#xff01; 1 以下代码的输出结果为&#xff1a; alist [1, 2, 3, 4] print(alist.reverse()) print(alist) A.[4, 3, 2, …

Python爬虫中的代理IP设置与实战策略

在Python爬虫中&#xff0c;使用代理IP设置是一种常见的策略&#xff0c;主要用于以下几个目的&#xff1a; 1. 避免被目标网站封禁&#xff1a;频繁的请求可能会引起目标网站的注意&#xff0c;导致你的IP被封锁。通过使用代理IP&#xff0c;你可以模拟来自不同地点和设备的请…

【WPF】使用Behavior以及ValidationRule实现表单校验

文章目录 使用ValidationRule实现检测用户输入EmptyValidationRule 非空校验TextBox设置非空校验TextBox设置非空校验并显示校验提示 结语 使用ValidationRule实现检测用户输入 EmptyValidationRule是TextBox内容是否为空校验&#xff0c;TextBox的Binding属性设置ValidationRu…

AR智慧校园三维主电子沙盘系统研究及应用

一 、概述 易图讯科技(www.3dgis.top)自主研发的智慧校园三维主电子沙盘系统&#xff0c;采用B/S架构模式&#xff0c;采用自主可控高性能WebGIS可视化引擎&#xff0c;支持多用户客户端通过网络请求访问服务器地图和专题数据&#xff0c;提供地理信息数据、专题数据的并发访问…

爬虫工作量由小到大的思维转变---<第二十八章 Scrapy中间件说明书>

爬虫工作量由小到大的思维转变---&#xff1c;第二十六章 Scrapy通一通中间件的问题&#xff1e;-CSDN博客 前言: (书接上面链接)自定义中间件玩不明白? 好吧,写个翻译的文档点笔记,让中间件更通俗一点!!! 正文: 全局图: 爬虫中间件--->翻译笔记: from scrapy import s…

ES慢查询分析——性能提升6 倍

问题 生产环境频繁报警。查询跨度91天的数据&#xff0c;请求耗时已经来到了30s。报警的阈值为5s。 背景 查询关键词简单&#xff0c;为‘北京’ 单次仅检索两个字段 查询时间跨度为91天&#xff0c;覆盖数据为450亿数据 问题分析 使用profle分析&#xff0c;复现监控报警的…

Go在Win10上接收UDP组播数据

第一步、绑定本机某张网卡的IP和端口&#xff0c;本代码选择IP为0.0.0.0&#xff0c;端口为8000&#xff1b;第二步、加入组播&#xff0c;组播地址为“224.0.0.1”&#xff1b;第三步、循环接收UDP组播数据&#xff1b; 代码 package mainimport ("fmt""golang…

从 Linux Crontab 到 K8s CronJob,定时任务正在经历怎样的变革

作者&#xff1a;黄晓萌(学仁) 背景 Job 表示短周期的作业&#xff0c;定时 Job 表示按照预定的时间运行Job&#xff0c;或者按照某一频率周期性的运行 Job。比如&#xff1a; 许多传统企业使用 Linux 自带的 crontab 来做定时任务的方案&#xff0c;该方案非常简单&#xff…

“巴渝工匠杯”2022年重庆市职业院校技能大赛(高职组)云计算样题

“巴渝工匠杯”2022年重庆市职业院校技能大赛&#xff08;高职组&#xff09;云计算样题 需要软件包环境可私信博主 【赛程名称】云计算赛项第一场次-私有云 某企业拟使用OpenStack搭建一个企业云平台&#xff0c;以实现资源池化弹性管理、企业应用集中管理、统一安全认证和授…

PostGIS学习教程十五:几何图形的有效性

PostGIS学习教程十五&#xff1a;几何图形的有效性 在90%的情况下&#xff0c;“为什么我的查询给了我一个’TopologyException’错误"的问题的答案是"一个或多个输入的几何图形是无效的”&#xff0c;这就引出了这样一个问题:几何图形"无效"是什么意思&a…

从计算机内存结构到iOS

一、冯.诺伊曼结构 当前计算机都是冯.诺伊曼结构&#xff08;Von Neumann architecture&#xff09;&#xff0c;是指存储器存放程序的指令以及数据&#xff0c;在程序运行时根据需要提供给CPU使用。 冯.诺伊曼瓶颈 在目前的科技水平之下&#xff0c;CPU与存储器之间的读写速…

【C Primer Plus第六版 学习笔记】第十四章 结构和其他数据形式

有基础&#xff0c;进阶用&#xff0c;个人查漏补缺 建立结构声明&#xff1a;描述该对象由什么组成&#xff0c;即结构布局 格式&#xff1a; 关键字 标记&#xff08;可选&#xff09;{结构 }&#xff1b; 举例&#xff1a; struct book{char title[2];char author[4];float …

Xcode 编译速度慢是什么原因?如何提高编译速度?

作为一个开发者&#xff0c;我们都希望能够高效地开发应用程序&#xff0c;而编译速度是影响开发效率的重要因素之一。然而&#xff0c;有时候我们会发现在使用 Xcode 进行开发时&#xff0c;译速度非常慢&#xff0c;这给我们带来了不少困扰。那么&#xff0c;为什么 Xcode 的…

分页合理化是什么?

一、前言 大家好&#xff01;我是sum墨&#xff0c;一个一线的底层码农&#xff0c;平时喜欢研究和思考一些技术相关的问题并整理成文&#xff0c;限于本人水平&#xff0c;如果文章和代码有表述不当之处&#xff0c;还请不吝赐教。 只要是干过后台系统的同学应该都做过分页查…

神经网络介绍

目录 知识点介绍 知识点介绍 前馈神经网络&#xff1a;&#xff08;前馈网络的数据只向一个方向传播&#xff09; RNN循环神经网络&#xff0c;下图中多个 RNN 层都是“同一个层”&#xff0c;这一点与之前的神经网络是不一样的。

怎么下载landsat 8影像并在ArcGIS Pro中进行波段组合

Landsat 8&#xff08;前身为Landsat数据连续性任务&#xff0c;或 LDCM&#xff09;于2013年2月11日由 Atlas-V火箭从加利福尼亚州范登堡空军基地发射升空&#xff0c;这里为大家介绍一下该数据的下载的方法&#xff0c;希望能对你有所帮助。 注册账号 如果之前已经注册过的…

5、IDEA集成Git

IDEA集成Git 1. 配置Git忽略文件2. 定位Git程序3. 初始化本地库、添加暂存区、提交到本地库4. 切换版本5. 创建分支和切换分支6. 合并分支7. 解决冲突 1. 配置Git忽略文件 问题1&#xff1a;为什么要忽略他们&#xff1f; 与项目的实际功能无关&#xff0c;不参与服务器上部署…