Java8实战-总结25

news2024/10/6 18:34:13

Java8实战-总结25

  • 用流收集数据
    • 归约和汇总
      • 查找流中的最大值和最小值
      • 汇总
      • 连接字符串
      • 广义的归约汇总

用流收集数据

归约和汇总

重用一下之前的例子:包含一张佳肴列表的菜单。

就像刚刚看到的,在需要将流项目重组成集合时,一般会使用收集器(Stream方法collect的参数)。再宽泛一点来说,但凡要把流中所有的项目合并成一个结果时就可以用。这个结果可以是任何类型,可以复杂如代表一棵树的多级映射,或是简单如一个整数——也许代表了菜单的热量总和。

先来举一个简单的例子,利用counting工厂方法返回的收集器,数一数菜单里有多少种菜:

long howManyDishes = menu.stream().collect(Collectors.counting();

这还可以写得更为直接:

long howManyDishes = menu.stream().count();

counting收集器在和其他收集器联合使用的时候特别有用。后面的部分,假定已导入了Collectors类的所有静态工厂方法:

import static java.util.stream.Collectors.*;

这样就可以写counting()而用不着写Collectors.counting()之类的了。继续探讨简单的预定义收集器,看看如何找到流中的最大值和最小值。

查找流中的最大值和最小值

假设想要找出菜单中热量最高的菜。可以使用两个收集器,Collectors.maxByCollectors.minBy,来计算流中的最大或最小值。这两个收集器接收一个Comparator参数来比较流中的元素。可以创建一个Comparator来根据所含热量对菜肴进行比较,并把它传递给Collectors.maxBy:

Comparator<Dish> dishcaloriesComparator = Comparator.comparingInt(Dish::getcalories);
 
Optional<Dish> mostCalorieDish = menu.stream().collect(maxBy(dishcaloriesComparator));

optional<Dish>是怎么回事。要回答这个问题,需要问“要是menu为空怎么办”。那就没有要返回的菜了。Java 8引入了optional,它是一个容器,可以包含也可以不包含值。这里它完美地代表了可能也可能不返回菜肴的情况。在讲findAny方法的时候简要提到过它。

另一个常见的返回单个值的归约操作是对流中对象的一个数值字段求和。或者可能想要求平均数。这种操作被称为汇总操作。让我们来看看如何使用收集器来表达汇总操作。

汇总

Collectors类专门为汇总提供了一个工厂方法:Collectors.summingInt。它可接受一个把对象映射为求和所需int的函数,并返回一个收集器;该收集器在传递给普通的collect方法后即执行需要的汇总操作。

举个例子来说,可以这样求出菜单列表的总热量:

int totalCalories = menu.stream().collect(summingInt(Dish::getcalories));

这里的收集过程如下图所示。在遍历流时,会把每一道菜都映射为其热量,然后把这个数字累加到一个累加器(这里的初始值0)。
Collectors.summingLongCollectors.summingDouble方法的作用完全一样,可以用于求和字段为longdouble的情况。
在这里插入图片描述
但汇总不仅仅是求和;还有Collectors.averagingInt,连同对应的averagingLongaveragingDouble可以计算数值的平均数:

double avgCalories = menu.stream().collect(averagingInt(Dish::getcalories));

到目前为止,已经看到了如何使用收集器来给流中的元素计数,找到这些元素数值属性的最大值和最小值,以及计算其总和和平均值。不过很多时候,可能想要得到两个或更多这样的结果,而且你希望只需一次操作就可以完成。在这种情况下,你可以使用summarizingInt工厂方法返回的收集器。例如,通过一次summarizing操作你可以就数出菜单中元素的个数,并得到菜肴热量总和、平均值、最大值和最小值:

IntSummaryStatistics menuStatistics = menu.stream().collect(summarizingInt(Dish::getcalories));

这个收集器会把所有这些信息收集到一个叫作IntSummaryStatistics的类里,它提供了方便的取值(getter)方法来访问结果。打印menuStatisticobject会得到以下输出:

IntSummaryStatistics{count=9, sum=4300, min=120, average=477.777778, max=800}

同样,相应的summarizingLongsummarizingDouble工厂方法有相关的LongSummaryStatisticsDoubleSummaryStatistics类型,适用于收集的属性是原始类型longdouble的情况。

连接字符串

joining工厂方法返回的收集器会把对流中每一个对象应用toString方法得到的所有字符串连接成一个字符串。这意味着把菜单中所有菜肴的名称连接起来,如下所示:

String shortMenu = menu.stream().map(Dish::getName).collect(joining());

请注意,joining在内部使用了StringBuilder来把生成的字符串逐个追加起来。此外还要注意,如果Dish类有一个toString方法来返回菜肴的名称,那无需用提取每一道菜名称的函数来对原流做映射就能够得到相同的结果:

String shortMenu = menu.stream().collect(joining());

二者均可产生以下字符串:

porkbeefchickenfrench friesriceseason fruitpizzaprawnssalmon

但该字符串的可读性并不好。幸好,joining工厂方法有一个重载版本可以接受元素之间的分界符,这样就可以得到一个逗号分隔的菜肴名称列表:

String shortMenu = menu.stream().map(Dish::getName).collect(joining(","));

正如我们预期的那样,它会生成:

pork, beef, chicken, french fries, rice, season fruit, pizza, prawns, salmon

到目前为止,已经探讨了各种将流归约到一个值的收集器。下面会展示为什么所有这种形式的归约过程,其实都是Collectors.reducing工厂方法提供的更广义归约收集器的特殊情况。

广义的归约汇总

事实上,已经讨论的所有收集器,都是一个可以用reducing工厂方法定义的归约过程的特殊情况而已。Collectors.reducing工厂方法是所有这些特殊情况的一般化。例如,可以用reducing方法创建的收集器来计算菜单的总热量,如下所示:

int totalcalories = menu.stream().collect(reducing(0, Dish::getcalories, (i, j) -> i + j));

它需要三个参数。

  • 第一个参数是归约操作的起始值,也是流中没有元素时的返回值,所以很显然对于数值和而言0是一个合适的值。
  • 第二个参数将菜肴转换成一个表示其所含热量的int
  • 第三个参数是一个Binaryoperator,将两个项目累积成一个同类型的值。这里它就是对两个int求和。

同样,可以使用下面这样单参数形式的reducing来找到热量最高的菜,如下所示:

Optional<Dish> mostcalorieDish = menu.stream().collect(reducing((d1, d2) -> d1.getcalories() > d2.getcalories() ? d1 : d2));

你可以把单参数reducing工厂方法创建的收集器看作三参数方法的特殊情况,它把流中的
第一个项目作为起点,把恒等函数(即一个函数仅仅是返回其输入参数)作为一个转换函数。这也意味着,要是把单参数reducing收集器传递给空流的collect方法,收集器就没有起点;正
如我们在6.2.1节中所解释的,它将因此而返回一个optional对象。

  1. 收集框架的灵活性:以不同的方法执行同样的操作

你还可以进一步简化前面使用reducing收集器的求和例子——引用Integer类的sum方法,而不用去写一个表达同一操作的Lambda表达式。这会得到以下程序:
在这里插入图片描述

在现实中,counting收集器也是类似地利用三参数reducing工厂方法实现的。它把流中的每个元素都转换成一个值为1Long型对象,然后再把它们相加:

public static <T> Collector<T,?,Long> counting(){
	return reducing(OL, e -> 1L, Long::sum);
}

还有另一种方法不使用收集器也能执行相同操作——将菜肴流映射为每一道菜的热量,然后用前一个版本中使用的方法引用来归约得到的流:

int totalcalories = menu.stream().map(Dish::getCalories).reduce(Integer::sum).get();

请注意,就像流的任何单参数reduce操作一样,reduce(Integer::sum)返回的不是int而是optional<Integer>,以便在空流的情况下安全地执行归约操作。然后只需用optional对象中的get方法来提取里面的值就行了。请注意,在这种情况下使用get方法是安全的,只是因为已经确定菜肴流不为空。一般来说,使用允许提供默认值的方法,如orElseorElseGet来解开optional中包含的值更为安全。最后,更简洁的方法是把流映射到一个IntStream,然后调用sum方法,也可以得到相同的结果:

int totalcalories = menu.stream().mapToInt(Dish::getCalories).sum();
  1. 根据情况选择最佳解决方案

这再次说明了,函数式编程(特别是Java 8Collections框架中加入的基于函数式风格原理设计的新API)通常提供了多种方法来执行同一个操作。这个例子还说明,收集器在某种程度上比Stream接口上直接提供的方法用起来更复杂,但好处在于它们能提供更高水平的抽象和概括,也更容易重用和自定义。

尽可能为手头的问题探索不同的解决方案,但在通用的方案里面,始终选择最专门化的一个。无论是从可读性还是性能上看,这一般都是最好的决定。例如,要计菜单的总热量,更倾向于最后一个解决方案(使用IntStream),因为它最简明,也很可能最易读。同时,它也是性能最好的一个,因为IntStream可以避免自动拆箱操作,也就是从Integerint的隐式转换,它在这里毫无用处。

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

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

相关文章

uniapp 小程序 全局弹窗 每个需要使用的页面都不用再引用

文章目录 创建组件在项目的根目录下的vue.config.vue中配置页面中使用 使用全局组件&#xff0c;先声明全局组件 与普通的组件声明不同之处在于 1&#xff1a;目录形式 2&#xff1a;声明引用方式 创建组件 在components目录中创建组件目录/组件vue&#xff0c;如下 注意需要同…

SpringMVC之综合案例:参数传递,向页面传参,页面跳转

参数传递向页面传参页面跳转 1.参数传递 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"htt…

【PyTorch 08】如果要手动安装对应的包

例如有时候我们要下载 PyG &#xff0c;但是需要手动下载&#xff0c;需要进行以下步骤&#xff1a; 网站链接&#xff1a;https://data.pyg.org/whl/ 首先查看当前安装好的Pytorch版本和对应的cuda版本 1. pip list&#xff1a;查看torch版本 2. torch.version.cuda&#xf…

3.4 栈与递归

3.4.1 采用递归算法解决问题 3.4 栈与递归的关系 栈和递归之间有着紧密的关系&#xff0c;特别是在算法和程序设计中。栈作为一种数据结构&#xff0c;可以有效地支持递归算法的实现。本节我们将详细讨论栈在递归算法中的作用及其在程序设计中的重要性。 1. 递归算法的基本概…

C#和.NET FrameWork概述

.NET FrameWork是什么&#xff1f; .NET FrameWork是由微软开发的一种面相对象的环境框架&#xff0c;特点如下&#xff1a; ①多平台&#xff1a;可在各种计算机、服务器、手机上运行。 ②标准化通讯协议&#xff1a;如XML、HTTP、JSON等。 ③安全性&#xff1a;CLR检查并…

通过实例学习鸿蒙静态库的创建与使用

简要介绍 静态共享包HAR&#xff08;Harmony Archive&#xff09;&#xff0c;是为了实现代码和资源的共享&#xff0c;可以包含代码、C库、资源和配置文件&#xff0c;随使用方一起编译&#xff0c;如果在多个应用中进行调用&#xff0c;就需要有多个HAR&#xff0c;和应用绑…

修改Tomcat的默认端口号

1、找到Tomcat的安装路径。 2、打开conf文件夹。 3、用记事本打开server.xml文件 4、找到 <Connector port"8080" protocol"HTTP/1.1"&#xff0c;其中的8080就是tomcat的默认端口&#xff0c;将其修改为你需要的端口即可。

图书管理信息系统分析与设计

一、系统开发的可行性分析 &#xff08;一&#xff09;系统背景.必要性及意义 随着社会经济的迅速发展和科学技术的全面进步&#xff0c;计算机事业的飞速发展&#xff0c;以计算机与通信技术为基础的信息系统正处于蓬勃发展的时期。随着经济文化水平的显著提高&#xff0c;人…

数据接口工程对接BI可视化大屏(六)接收前台数据

文章目录 第6章 接收前台数据6.1 模拟数据6.2 接收数据6.2.1 编写Dao6.2.2 编写ServiceImpl6.2.3 编写Controller6.2.4 验证 后记 第6章 接收前台数据 在工作中也会遇到需要接收前台发送数据&#xff0c;进行存储的情况。这里以接收日志服务器的日志数据保存到kafka为例。 6.…

久运恒远聚焦物业多营渠道致力服务美好生活

随着社会的不断发展和人民生活水平的不断提高&#xff0c;物业行业已经逐渐向深度服务化方向调整&#xff0c;物业的多种经营体系也成为品牌关注和布局的重要销售渠道。久运恒远&#xff08;北京&#xff09;企业管理有限公司聚焦物业多营体系&#xff0c;整合资源&#xff0c;…

CTFHub | 综合过滤练习

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…

简单5步骤搞定windows server2019 配置IIS支持PHP

测试成功&#xff0c;记录一笔&#xff0c;感谢网上各位大佬的技术支持。 一、安装vcredist_x64.exe 否则可能会出现 FastCGI进程意外退出 二、IIS开启CGI&#xff08;可能需要重启&#xff09; 控制面板&#xff0c;启用或关闭windows程序&#xff0c;IIS--应用程序开发--CGI…

61、SpringBoot -----跨域资源的设置----局部设置和全局设置

★ 跨域资源共享的意义 ▲ 在前后端分离的开发架构中&#xff0c;前端应用和后端应用往往是彻底隔离的&#xff0c;二者不在同一个应用服务器内、甚至不再同一台物理节点上。 因此前端应用和后端应用就不在同一个域里。▲ 在这种架构下&#xff0c;前端应用可能采用前端框架&a…

Linux入门教程||Linux系统目录结构

登录系统后&#xff0c;在当前命令窗口下输入命令&#xff1a; ls / 你会看到如下图所示: 树状目录结构&#xff1a; 以下是对这些目录的解释&#xff1a; /bin&#xff1a; bin是Binary的缩写, 这个目录存放着最经常使用的命令。 /boot&#xff1a; 这里存放的是启动Linux时…

【AIGC专题】Stable Diffusion 从入门到企业级实战0601

一、前言 本章是《Stable Diffusion 从入门到企业级实战》系列的第六部分Prompt专题篇《Stable Diffusion Prompt 专题》第01节 《Stable Diffusion Prompt 通用画风操作实战》。本部分内容&#xff0c;位于整个Stable Diffusion生态体系的位置如下图黄色部分所示&#xff1a;…

RJ45水晶头网线顺序出错排查

线序 网线水晶头RJ45常用的线序标准ANSI / TIA-568定义了T568A与T568B两种线序&#xff0c;一般使用T568B&#xff0c;水晶头8个孔对应的8条线颜色如下图&#xff1a; 那1至8的编号&#xff0c;是从水晶头哪一面为参考呢&#xff0c;如下图&#xff0c;是水晶头金手指一面&am…

SAP ABAP基础知识 访问外部数据库-开发篇

前言 本文主要介绍通过ABAP语言访问外部数据库的几种方式 一、外部数据库配置 本文示例中的代码访问了两个外部数据库 MTD : 外部oracle数据库,其中示例表 ZTTEMP 字段( ZZTNO,WERKS) S4Q : 外部HANA数据库(开发系统访问测试系统的数据库), 使用表USR02,ZTTEMP 二、ABAP访问…

YOLO物体检测系列2:YOLOV2整体解读

1、YOLOV1 优点&#xff1a;快速&#xff0c;简单&#xff01;问题1&#xff1a;每个Cell只预测一个类别&#xff0c;如果重叠无法解决问题2&#xff1a;小物体检测效果一般&#xff0c;长宽比可选的但单一 YOLOV2更快&#xff01;更强&#xff01; 2、Batch Normalization …

群晖NAS教程(二十五)、利用web station安装nextcloud

群晖NAS教程(二十五)、利用web station安装nextcloud 一、下载离线安装包文件 下载地址https://download.nextcloud.com/server/releases/&#xff0c;我们选择zip格式的&#xff0c;下载这个latest-27.zip的最新版的。 把它加压缩到群辉web/hepnextcloud路径下&#xff0c;并…

算法:贪心---跳一跳

1、题目&#xff1a; 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 2…