Java8实战-总结22

Java8实战-总结22

  • 使用流
    • 数值流
      • 原始类型流特化
      • 数值范围
      • 数值流应用:勾股数

使用流

数值流

可以使用reduce方法计算流中元素的总和。例如,可以像下面这样计算菜单的热量:

int calories = menu.stream().map(Dish::getcalories).reduce(0, Integer::sum);

这段代码的问题是,它有一个暗含的装箱成本。每个Integer都必须拆箱成一个原始类型,再进行求和。要是可以直接像下面这样调用sum方法,效果会更好:

int calories = menu.stream().map(Dish::getcalories).sum();

但这是不可能的。问题在于map方法会生成一个Stream<T>。虽然流中的元素是Integer类型,但Streams接口没有定义sum方法。Stream API提供了原始类型流特化,专门支持处理数值流的方法。

原始类型流特化

Java 8引入了三个原始类型特化流接口来解决这个问题:IntStreamDoubleStreamLongStream,分别将流中的元素特化为intlongdouble,从而避免了暗含的装箱成本。每个接口都带来了进行常用数值归约的新方法,比如对数值流求和的sum,找到最大元素的max。此外还有在必要时再把它们转换回对象流的方法。要记住的是,这些特化的原因并不在于流的复杂性,而是装箱造成的复杂性——即类似intInteger之间的效率差异。

  1. 映射到数值流

将流转换为特化版本的常用方法是mapToIntmapToDoublemapToLong。这些方法和前面说的map方法的工作方式一样,只是它们返回的是一个特化流,而不是stream<T>。例如,可以像下面这样用mapToIntmenu中的卡路里求和:

int calories = menu.stream().mapToInt(Dish::getcalories)//返回一个IntStream.sum();//返回一个Stream<Dish>

这里,mapToInt会从每道菜中提取热量(用一个Integer表示),并返回一个IntStream(而不是一个Stream<Integer>)。然后就可以调用IntStream接口中定义的sum方法,对卡路里求和了!请注意,如果流是空的,sum默认返回0IntStream还支持其他的方便方法,如maxminaverage等。

  1. 转换回对象流

同样,一旦有了数值流,也可以把它转换回非特化流。例如,IntStream上的操作只能产生原始整数:IntStreammap操作接受的Lambda必须接受int并返回int(一个IntUnaryoperator)。但是可能想要生成另一类值,比如Dish。为此,需要访问stream接口中定义的那些更广义的操作。要把原始流转换成一般流(每个int都会装箱成一个Integer),可以使用boxed方法,如下所示:
将Stream转

IntStream intStream = menu.stream().mapToInt(Dish::getcalories);//将Stream转换为数值流
Stream<Integer> stream = intStream.boxed();//将数值流转换为Stream

在需要将数值范围装箱成为一个一般流时,boxed尤其有用。

  1. 默认值optionalInt

求和的例子很容易,因为它有一个默认值:0。但是,如果要计算IntStream中的最大元素,就得换个法子了,因为0是错误的结果。如何区分没有元素的流和最大值真的是0的流呢?前面介绍了optional类,这是一个可以表示值存在或不存在的容器。Optional可以用IntegerString等参考类型来参数化。对于三种原始流特化,也分别有一个optional原始类型特化版本:optionalIntoptionalDoubleoptionalLong
例如,要找到IntStream中的最大元素,可以调用max方法,它会返回一个optionalInt:

OptionalInt maxCalories = menu.stream().mapToInt(Dish::getcalories).max();

现在,如果没有最大值的话,就可以显式处理optionalInt去定义一个默认值了:

int max = maxCalories.orElse(1);如果没有最大值的话,显式提供一个默认最大值

数值范围

和数字打交道时,有一个常用的东西就是数值范围。比如,假设想要生成1和100之间的所有数字。Java 8引入了两个可以用于IntStreamLongStream的静态方法,帮助生成这种范围:rangerangeClosed。这两个方法都是第一个参数接受起始值,第二个参数接受结束值。但range是不包含结束值的,而rangeClosed则包含结束值。例子:

//表示范围[1,100]
IntStream evenNumbers = IntStream.rangeclosed(1, 100).filter(n -> n % 2 == 0);//一个从1到100的偶数流System.out.println(evenNumbers.count());//从1到100有50个偶数

这里用了rangeClosed方法来生成1100之间的所有数字。它会产生一个流,然后可以链接filter方法,只选出偶数。到目前为止还没有进行任何计算。最后,对生成的流调用count。因为count是一个终端操作,所以它会处理流,并返回结果50,这正是1100(包括两端)中所有偶数的个数。请注意,比较一下,如果改用IntStream.range(1, 100),则结果将会是49个偶数,因为range是不包含结束值的。

数值流应用:勾股数

现在来看一个难一点儿的例子。

  1. 勾股数

某些三元数(a,b,c)满足公式a * a + b * b = c * c,其中a、b、c都是整数。例如,(3, 4, 5)就是一组有效的勾股数,因为3 * 3 + 4 * 4 = 5 * 59 + 16 = 25。这样的三元数有无限组。例如,(5 , 12, 13)(6, 8, 10)(7, 24, 25)都是有效的勾股数。勾股数很有用,因为它们描述的正好是直角三角形的三条边长,如下图所示:
在这里插入图片描述

  1. 表示三元数

第一步是定义一个三元数。虽然更恰当的做法是定义一个新的类来表示三元数,但这里可以使用具有三个元素的int数组,比如new int[]{3, 4, 5},来表示勾股数(3, 4, 5)。现在就可以用数组索引访问每个元素了。

  1. 筛选成立的组合

假定提供了三元数中的前两个数字:ab。怎么知道它是否能形成一组勾股数呢?需要测试a * a + b * b的平方根是不是整数,也就是说它没有小数部分——在Java里可以使用expr % 1表示。如果它不是整数,那就是说c不是整数。可以用filter操作表达这个要求:

filter(b -> Math.sqrt(a * a + b * b) % 1 == 0)

假设周围的代码给a提供了一个值,并且stream提供了b可能出现的值,filter将只选出那些可以与a组成勾股数的bMath.sqrt(a * a + b * b) %1 == 0这一行是一种测试Math.sqrt(a * a + b * b)返回的结果是不是整数的方法。如果平方根的结果带了小数,这个条件就不成立。

  1. 生成三元组

在筛选之后,知道ab能够组成一个正确的组合。现在需要创建一个三元组。可以使用map操作,像下面这样把每个元素转换成一个勾股数组:

stream.filter(b -> Math.sqrt(a*a + b*b) % 1 == 0).map(b -> new int[]{a, b, (int)Math.sqrt(a*a + b*b)});
  1. 生成b值

现在需要生成b的值。前面已经看到,Stream.rangeClosed可以在给定区间内生成一个数值流。可以用它来给b提供数值,这里是1100:

IntStream.rangeClosed(1, 100).filter(b -> Math.sqrt(a*a + b*b) % 1 == 0).boxed().map(b -> new int[]{a, b, (int)Math.sqrt(a*a + b*b)});

filter之后调用boxed,从rangeClosed返回的IntStream生成一个Stream<Integer>。这是因为map会为流中的每个元素返回一个int数组。而IntStream中的map方法只能为流中的每个元素返回另一个int,这不是想要的。可以用IntStreammapToObj方法改写它,这个方法会返回一个对象值流:

IntStream.rangeClosed(1, 100).filter(b -> Math.sqrt(a*a + b*b) % 1 == 0).mapToobj(b -> new int[]{a, b, (int)Math.sqrt(a*a + b*b)});

6 . 生成值

这里有一个关键的假设:给出了a的值。 现在,只要已知a的值,就有了一个可以生成勾股数的流。就像b一样,需要为a生成数值。最终的解决方案如下所示:

Streamcint[]> pythagoreanTriples = IntStream.rangeClosed(1, 100).boxed().flatMap(a ->IntStream.rangeClosed(a, 100).filter(b -> Math.sqrt(a*a + b*b) % 1 == 0).mapToobj(b ->new int[]{a, b, (int)Math.sqrt(a * a + b* b)})
);

首先,创建一个从1100的数值范围来生成a的值。对每个给定的a值,创建一个三元数流。要是把a的值映射到三元数流的话,就会得到一个由流构成的流。flatMap方法在做映射的同时,还会把所有生成的三元数流扁平化成一个流。这样就得到了一个三元数流。还要注意,b的范围改成了a100。没有必要再从1开始了,否则就会造成重复的三元数,例如(3,4,5)(4,3,5)

  1. 运行代码

现在可以运行解决方案,并且可以利用前面的limit命令,明确限定从生成的流中要返回多少组勾股数了:

pythagoreanTriples.limit(5).forEach(t ->System.out.println(t[0] + "," + t[1] + "," + t[2]));

这会打印:

3, 4, 5
5, 12, 13
6, 8, 10
7, 24, 25
8, 15, 17
  1. 最优

目前的解决办法并不是最优的,因为要求两次平方根。让代码更为紧凑的一种可能的方法是,先生成所有的三元数(a*a, b*b, a*a + b*b),然后再筛选符合条件的:

Streamcdouble[]> pythagoreanTriples2 =IntStream.rangeClosed(1, 100).boxed().flatMap(a ->IntStream.rangeClosed(a,100).mapToObj(b -> new double[]{a, b, Math.sqrt(a*a + b*b)})//产生三元数.filter(t -> t[2] % 1 == 0));//元组中的第三个元素必须是整数

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

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

相关文章

使用spring自带的发布订阅机制来实现消息发布订阅

背景 公司的项目以前代码里面有存在使用spring自带发布订阅的代码&#xff0c;因此稍微学习一下如何使用&#xff0c;并了解一下这种实现方式的优缺点。 优点 实现方便&#xff0c;代码方面基本只需要定义消息体和消费者&#xff0c;适用于小型应用程序。不依赖外部中间件&a…

msvcr120.dll放在哪里?怎么修复msvcr120.dll文件

当您在运行某些应用程序或游戏时遇到“msvcr120.dll缺失”错误时&#xff0c;这可能会影响您的使用体验。msvcr120.dll是Microsoft Visual C Redistributable的一部分&#xff0c;并且它提供了程序运行所需的运行时支持&#xff0c;今天我们来讨论一下msvcr120.dl文件缺失了要怎…

祝贺埃文科技入选河南省工业企业数据安全技术支撑单位

近日&#xff0c;河南省工业信息安全产业发展联盟公布了河南省工业信息安全应急服务支撑单位和河南省工业企业数据安全技术支撑单位遴选结果,最终评选出19家单位作为第一届河南省工业信息安全应急服务支撑单位和河南省工业企业数据安全技术支撑单位。 埃文科技凭借自身技术优势…

leetcode 20.有效括号 栈的简单应用

题目 数据结构 栈 code var isValid function(s) {// 空串和长度为奇数的字符串一定不符合要求if(!s || s.len%2){return true}let match {(: ),[: ],{: }}let stack []let len s.lengthfor(let i0; i<len; i){const ch s[i]if(ch[ || ch( || ch{){// 如果是左括号,…

2.k8s账号密码登录设置

文章目录 前言一、启动脚本二、配置账号密码登录2.1.在hadoop1&#xff0c;也就是集群主节点2.2.在master的apiserver启动文件添加一行配置2.3 绑定admin2.4 修改recommended.yaml2.5 重启dashboard2.6 登录dashboard 总结 前言 前面已经搭建好了k8s集群&#xff0c;现在设置下…

python Playwright优化页面等待和处理异步操作

在使用 Playwright 进行页面自动化时&#xff0c;优化页面等待和处理异步操作是非常重要的&#xff0c;可以提高脚本的稳定性和执行效率。 优化页面等待和处理异步操作的建议 **1. 使用正确的等待条件&#xff1a;**Playwright 提供了多种等待条件&#xff0c;如等待元素出现…

2023年9月软考高级信息系统项目管理师认证报名找弘博创新

信息系统项目管理师是全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;项目之一&#xff0c;是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试&#xff0c;既属于国家职业资格考试&#xff0c;又是职称资…

Excel VSTO开发8 -相关控件

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 8 相关控件 在VSTO开发中&#xff0c;Ribbon&#xff08;或称为Ribbon UI&#xff09;是指Office应用程序中的那个位于顶部的带有选…

Python实现猎人猎物优化算法(HPO)优化BP神经网络分类模型(BP神经网络分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 猎人猎物优化搜索算法(Hunter–prey optimizer, HPO)是由Naruei& Keynia于2022年提出的一种最新的…

【C++】—— 单例模式详解

前言&#xff1a; 本期&#xff0c;我将要讲解的是有关C中常见的设计模式之单例模式的相关知识&#xff01;&#xff01; 目录 &#xff08;一&#xff09;设计模式的六⼤原则 &#xff08;二&#xff09;设计模式的分类 &#xff08;三&#xff09;单例模式 1、定义 2、…

【数学建模竞赛】优化类赛题常用算法解析

优化类建模 问题理解和建模&#xff1a;首先&#xff0c;需要深入理解问题&#xff0c;并将问题抽象为数学模型。这包括确定问题的目标函数、约束条件和决策变量。 模型分析和求解方法选择&#xff1a;对建立的数学模型进行分析&#xff0c;可以使用数学工具和方法&#xff0c;…

【vue】使用无障碍工具条(详细)

引入&#xff1a;使用的是太阳湾的无障碍工具条&#xff0c;代码地址&#xff1a;https://gitee.com/tywAmblyopia/ToolsUI 具体步骤&#xff1a;下载代码后&#xff0c;将其中的 canyou 文件夹拖入 vue 项目中的 public 文件夹中&#xff1b; 上图是在项目目录中的样子&#…

【计算机视觉项目实战】中文场景识别

✨专栏介绍: 经过几个月的精心筹备,本作者推出全新系列《深入浅出OCR》专栏,对标最全OCR教程,具体章节如导图所示,将分别从OCR技术发展、方向、概念、算法、论文、数据集等各种角度展开详细介绍。 👨‍💻面向对象: 本篇前言知识主要介绍深度学习知识,全面总结知知识…

Android Ble蓝牙App(七)扫描过滤

Ble蓝牙App&#xff08;七&#xff09;扫描过滤 前言目录正文一、增加菜单二、使用MMKV① 添加依赖② 封装MMKV③ 使用MMKV 三、过滤空设备名四、过滤Mac地址五、过滤RSSI六、源码 前言 在上一篇文章中了解了MTU的相关知识以及对于设备操作信息的展示&#xff0c;本篇文章中将增…

基于SSM的校园驿站管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Android Studio开发入门教程:如何更改APP的图标?

更改APP的图标&#xff08;安卓系统&#xff09; 环境&#xff1a;Windows10、Android Studio版本如下图、雷电模拟器。 推荐图标库 默认APP图标 将新图标拉进src/main/res/mipmap-hdpi文件夹&#xff08;一般app的icon图标是存放在mipmap打头的文件夹下的&#xff09; 更改sr…

NoSQL技术——Redis

简单介绍 Redis是当下最流行的NoSQL数据库。在Redis中&#xff0c;数据的存储格式是以键值对的方式进行存储的。在键值对的存储形式中&#xff0c;值除了是常见的字符串&#xff0c;也可以是类似于Json对象的形式&#xff0c;或者是List&#xff0c;Map等数组格式&#xff0c;…

leetcode 92.反转链表II dummy节点的应用

题目 方法 dummy节点 链表的第一个结点&#xff0c;因为没有前驱结点&#xff0c;存在同时删除前驱和后继的情况&#xff0c;这时候我们需要人为构造dummy节点——人为制造出来的第一个结点的前驱结点&#xff0c;也就是说&#xff0c;在可能操作head节点时&#xff0c;我们可…

【CAD二次开发】重新加载acad.pgp快捷菜单文件

为了加快绘图速度&#xff0c;好多人会进行CAD快捷命令的修改&#xff0c;那怎么在不需要重启CAD的情况下自动更新&#xff1f; CAD修改acad.pgp,快捷命令后&#xff0c;自动更新。 方法一 命令行输入reinit&#xff0c;命令。 在弹出的窗口中&#xff0c;选择‘PGP文件’&…

腾讯汤道生:超千亿参数 超2万亿tokens 腾讯混元大模型向行业全面开放

9月7日&#xff0c;2023腾讯全球数字生态大会在深圳宝安举行。腾讯集团高级执行副总裁、云与智慧产业事业群CEO汤道生表示&#xff0c;腾讯将迈入“全面拥抱大模型”时代&#xff1a;“以大模型生成技术为核心&#xff0c;人工智能正在成为下一轮数字化发展的关键动力&#xff…