Stream.reduce()用法详细解析

news/2024/4/25 19:35:36/文章来源:https://blog.csdn.net/weixin_44688973/article/details/127251061

在学习这个函数的用法之前,我们要先知道这个函数参数的意义

基本使用

先举一个简单的例子:

算法题:Words
题目描述
每个句子由多个单词组成,句子中的每个单词的长度都可能不一样,我们假设每个单词的长度Ni为该单词的重量,你需要做的就是给出整个句子的平均重量V。解答要求
时间限制:1000ms, 内存限制:100MB
输入
输入只有一行,包含一个字符串S(长度不会超过100),代表整个句子,句子中只包含大小写的英文字母,每个单词之间有一个空格。输出
输出句子S的平均重量V(四舍五入保留两位小数)。Who Love Solo
输出样例 
3.67

这道题的意思是求一句话中每个单词的平均长度,我们求得总长度然后除以单词数量即可,刚好能用到reduce()这个方法。

public class Demo {public static void main(String[] args) {Scanner sc = new Scanner(System.in);String[] s = sc.nextLine().split(" ");double res = Arrays.stream(s).mapToDouble(a ->a.length()).reduce(0,(a,b)->a+b);System.out.println(String.format("%.2f",res/s.length));}
}

在代码中,.reduce(0,(a,b)->a+b);这一块就是我们经典的使用案例,我们要先明白其中a,b的含义,然后再学习如何使用
关键概念:初始值的定义(Identity),累加器(Accumulator),组合器(Combiner)

  • Identity : 定义一个元素代表是归并操作的初始值,如果Stream 是空的,也是Stream 的默认结果
  • Accumulator: 定义一个带两个参数的函数,第一个参数是上个归并函数的返回值,第二个是Strem 中下一个元素。
  • Combiner: 调用一个函数来组合归并操作的结果,当归并是并行执行或者当累加器的函数和累加器的实现类型不匹配时才会调用此函数。

也就是说0就是我们的初始值,(a,b)->a+b就是我们的累加器,其中a就是上一次的计算结果,b就是Stream流中当前元素,而后面的a+b则是计算规则,比如如果我们改成a*b,那就是计算乘积了,当然我们也可以用方法引用来代替 lambda 表达式。

double res = Arrays.stream(s).mapToDouble(a ->a.length()).reduce(0,Double::sum);

这就是最基本的使用了,不知道小伙伴们有没有学会呢?

额外举例

当然,我们可以用reduce 方法处理其他类型的 stream,例如,可以操作一个 String 类型的数组,把数组的字符串进行拼接。

List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result = letters.stream().reduce("", (partialString, element) -> partialString + element);
assertThat(result).isEqualTo("abcde");

同样也可以用方法引用来简化代码

String result = letters.stream().reduce("", String::concat);
assertThat(result).isEqualTo("abcde");

我们再把上面的拼接字符串的例子改下需求,先把字符串转变成大写然后再拼接

String result = letters.stream().reduce("", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase());
assertThat(result).isEqualTo("ABCDE");

另外,我们可以并行地归并元素(并行归并,下面会详细讲解),如下并行归并一个数字数组来求和

List<Integer> ages = Arrays.asList(25, 30, 45, 28, 32);
int computedAges = ages.parallelStream().reduce(0, a, b -> a + b, Integer::sum);

当对一个流进行并行操作时,在运行时会把流分割多个子流来并行操作。在上面例子中,我们需要一个函数来组合各个子流返回的结果,这个函数就是前面提到的Combiner(组合器)。
有一个注意点,下面的代码无法通过编译

List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge());

上代码无法编译的原因是,流中包含的是User 对象,但是累加函数的参数分别是数字和user 对象,而累加器的实现是求和,所以编译器无法推断参数 user 的类型。可以把代码改为如下可以通过编译

int result = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
assertThat(result).isEqualTo(65);

当顺序读流或者累加器的参数和它的实现的类型匹配时,我们不需要使用组合器。

并行读流

如上文提到的,我们可以并行的使用 reduce() 方法。并行使用时,要注意一下几点:

  • 结果和处理的顺序无关
  • 操作不影响原有数据
  • 操作没有状态和同样的输入有一样的输出结果
    我们注意上面3点,以防出现不预期的结果,一般并行处理包含大量数据的流或者耗时的操作。

处理异常

在以上的例子中,reduce 方法都没抛出异常,如果出现异常我们该如何优雅的处理异常呢?看下面例子:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int divider = 2;
int result = numbers.stream().reduce(0, a / divider + b / divider);

如果 divider =0 , 会抛出 ArithmeticException,遇到这种情况,一般的处理方法使用 try/catch 捕获异常

public static int divideListElements(List<Integer> values, int divider) {return values.stream().reduce(0, (a, b) -> {try {return a / divider + b / divider;} catch (ArithmeticException e) {LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero");}return 0;});
}

如果直接使用 try/catch 会影响代码的可读性,我们可以把 divide 的操作封装一个单独的方法,并在里面捕获异常,如下:

rivate static int divide(int value, int factor) {int result = 0;try {result = value / factor;} catch (ArithmeticException e) {LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero");}return result
}

divideListElements 调用 divide 方法

public static int divideListElements(List<Integer> values, int divider) {return values.stream().reduce(0, (a, b) -> divide(a, divider) + divide(b, divider));
}

复杂对象的处理

我们可以使用 reduce 方法处理复杂的对象,reduce 需要接受和复杂对象相对应的 identity、accumulator、combiner。
假设一个场景:计算一个网站用户的评分,该评分是所有用户所有评论的平均值。
有个类 Review 定义如下:

public class Review {private int points;private String review;// constructor, getters and setters
}

类 Rating 引用 Review 计算用户的评分

public class Rating {double points;List<Review> reviews = new ArrayList<>();public void add(Review review) {reviews.add(review);computeRating();}private double computeRating() {double totalPoints = reviews.stream().map(Review::getPoints).reduce(0, Integer::sum);this.points = totalPoints / reviews.size();return this.points;}public static Rating average(Rating r1, Rating r2) {Rating combined = new Rating();combined.reviews = new ArrayList<>(r1.reviews);combined.reviews.addAll(r2.reviews);combined.computeRating();return combined;}}

先组装一些用户和用户的评论

User john = new User("John", 30);
john.getRating().add(new Review(5, ""));
john.getRating().add(new Review(3, "not bad"));
User julie = new User("Julie", 35);
john.getRating().add(new Review(4, "great!"));
john.getRating().add(new Review(2, "terrible experience"));
john.getRating().add(new Review(4, ""));
List<User> users = Arrays.asList(john, julie);

调用 reduce 方法处理评分

Rating averageRating = users.stream().reduce(new Rating(), (rating, user) -> Rating.average(rating, user.getRating()), Rating::average);

不知道大家学会了吗?
别忘了给个赞b( ̄▽ ̄)d

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

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

相关文章

SkeyeVSS智慧国土高点视频监控解决方案

随着经济的快速发展、城镇化的快速推进&#xff0c;耕地及矿产资源等不断减少&#xff0c;未批先建、批少用多、私自改变土地用途等各种违法违规用地行为时有发生&#xff0c;在这种情况下&#xff0c;传统的人力巡查工作效率低、执法成本高的弊端进一步凸显。 SkeyeVSS智慧国土…

科技云报道:私有云市场加速洗牌,超云为何异军突起?

科技云报道原创。 近年来在国家相关政策的大力推动下&#xff0c;中国私有云市场发展渐入佳境&#xff0c;一股新的建设高潮汹涌而至。 根据IDC对于2022-2026中国SDS及HCI的市场预测&#xff0c;中国私有云基础架构市场正在从成长阶段迈向成熟阶段&#xff0c;未来3-5年将保持…

自己动手写ls命令——Java版

自己动手写ls命令——Java版 介绍 在前面的文章Linux命令系列之ls——原来最简单的ls这么复杂当中&#xff0c;我们仔细的介绍了关于ls命令的使用和输出结果&#xff0c;在本篇文章当中我们用Java代码自己实现ls命令&#xff0c;更加深入的了解ls命令。 代码实现 文件操作的…

3000字神经网络论文

你遇到了哪些困难和挫折是怎样克服的写下来的作文 我学会了骑自行车人生的道路上&#xff0c;谁都会遇到困难或挫折&#xff0c;就看你敢不敢去挑战它。那一次学自行车&#xff0c;一直让我记忆犹新。一天傍晚&#xff0c;我和爸爸妈妈一起推着车来到体育馆&#xff0c;这次我…

Android同文输入法的使用(开源输入法Trime)

Trime输入法背景源码APP试用下载安装配置部署成功后再一步&#xff1a;学习如何 DIY总结背景 想找一款开源的Android中文输入法&#xff0c;然后发现了这款备受推崇的输入法框架rime。 RIME&#xff0f;中州韵输入法引擎&#xff0c;是一个跨平台的输入法算法框架。 基于这一…

【MySQL】检索数据

每日鸡汤 &#xff1a; —— 若你困于无风之地&#xff0c;我将奏响高空之歌 要和我一起花 10 min 学一会 SQL 嘛&#xff1f; - 当然愿意&#xff0c;我美丽的小姐 &#xff08;封寝期间练就的自言自语能力越来越炉火纯青了~~~&#xff09; 前言&#xff1a; 本实验中所用数据…

Kotlin第二章:kotlin基础

1. 基础数据类型 1. 整数类型 序号类型位宽最小值最大值1Byte8-1281272Short16-32768327673Int32-2,147,483,648 (-2^31)2,147,483,647 (2^31 - 1)4Long64-9,223,372,036,854,775,808 (-2^63)9,223,372,036,854,775,807 (2^63 - 1) val number 100 //默认Int类型 类比java的…

0050 Enum枚举类

/* 枚举是一种特殊的类&#xff0c;里面只包含一组有限的特定对象枚举的两种实现方式1.自定义类实现枚举2.使用enum关键字实现枚举自定义类实现枚举1.构造器私有化2.本类的内部创建一组对象[]3.对外暴露对象&#xff08;为对象添加public final static修饰&#xff09;4.提供g…

第三章 Flink基础理论之内存优化及常见内存报错解决方案

第三章 Flink基础理论之内存优化及常见内存报错解决方案 哇. 1、总体内存模型 1.1、内存模型概述 ​ Flink内存配置分为JobManager内存配置和TaskManager内存配置。 配置项TaskManager配置参数JobManager配置参数Total Flink Memorytaskmanager.memory.flink.sizejobmana…

土方量计算的准确作法

​现在说到土方量结算&#xff0c;绝大多数土木行业的人都说某某软件很方便&#xff0c;但是我要问到手算会吗&#xff0c;大多数人都会支支吾吾&#xff0c;虽然手算确实不现实&#xff0c;但是我们做为专业人员&#xff0c;总不能沦为软件使用者吧&#xff1f;其中的原理大家…

公众号网课题库系统-注册即可使用

公众号网课题库系统-注册即可使用 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 题库&#xff1a;题库后台&#xff08;点击跳转…

大数据专题-spark mysql python爬虫携程景点爬取(含虚拟机镜像)

博主介绍&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域✌ 项目名称 大数据专题-spark mysql python爬虫携程景点爬取&#xff08;含虚拟机镜像&#xff09; 视频效果 大数据专题-spark mysql python爬虫携程景点系统说明 一&…

Vue组件之间的数据共享详解

目录前言一&#xff0c;props的作用二&#xff0c;父向子传值2.1 子元素2.2 父元素2.3 整体代码三&#xff0c;子向父传值3.1 子组件3.2 父组件3.3 整体代码四&#xff0c;兄弟之间的数据传递4.1 事件总线EventBus介绍(面试高频&#xff09;4.2 传值方4.3 接收方后记前言 组件…

Servlet - Filtering (过滤器))

[TOC](Servlet - Filtering (过滤器) ) 1. What 1.1 什么是Filter Servlet过滤器Filter是一个小型的web组件&#xff0c;它们通过拦截请求和响应&#xff0c;以便查看、提取或以某种方式操作客户端和服务器之间交换的数据&#xff0c;实现“过滤”的功能。Filter通常封装了一…

深度神经网络的优化算法,进化算法优化神经网络

有哪些手段可以提升深度神经网络的泛化性能 人工神经网络以其智能性见长&#xff0c;那么神经网络能真的学到一个映射的本质吗&#xff1f;也就是说&#xff0c;对一个映射给出一定的必要的训练样本训练后&#xff0c;网络能否对样本以外的样本给出较为准确的预测。 泛化能力…

概率论与数理统计学习:随机向量(三)——知识总结与C语言实现案例

hello&#xff0c;大家好 这里是第八期概率论与数理统计的学习&#xff0c;我将用这篇博客去总结这期的知识点以及实现用C语言去做题的过程。 本期知识点&#xff1a; 条件分布 条件分布的概念离散型随机变量的条件概率分布连续型随机变量的条件概率密度 随机变量的独立性 那…

ROS学习笔记三(TF的类)

1.数据类型 数据类型定义在tf/transform_datatypes.h.里 1.1 基本数据类型(Quaternion, Vector, Point, Pose, Transform) TypetfQuaterniontf::QuaternionVectortf::Vector3Pointtf::PointPosetf::PoseTransformtf::Transform 1.2 tf::Stamped tf::Stamped在上面的数据类型…

RocketMQ 5.0:无状态代理模式的探索与实践

本文作者&#xff1a;金吉祥&#xff0c; Apache RocketMQ PMC Member&#xff0c;阿里云智能高级技术专家 背景 首先&#xff0c;让我们来看下是遇到了哪些痛点问题&#xff0c;促使我们去探索一种无状态代理的RocketMQ新架构的&#xff1b; RocketMQ 拥有一套极简的架构&am…

安卓投屏 QtScrcpy

一、电脑安装adb 版本大于1.0.40以上 40不行 adb 1.0.41下载链接 链接&#xff1a;https://pan.baidu.com/s/1WIPI-p7a4ErTLFYHaTC2kw?pwdadbt 提取码&#xff1a;adbt 安装参考 https://blog.csdn.net/M7_xbc/article/details/122957311 二、打开无线调试并且配对 手机打…

驱动开发(10/10-林雪阵)

终端输入1--->LED1点亮 终端输入2--->LED2点亮 终端输入3--->LED3点亮 终端输入0--->LED熄灭 chdev.c (底层驱动代码&#xff09; #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h>…