我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java Stream.reduce()用法详细解析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java Stream.reduce()用法详细解析

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

基本使用

先举一个简单的例子:

算法题: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);

不知道大家学会了吗?

总结

到此这篇关于Java Stream.reduce()用法的文章就介绍到这了,更多相关Stream.reduce()用法内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java Stream.reduce()用法详细解析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java Stream.reduce()用法详细解析

StreamAPI提供了丰富的中间函数,归并函数和终端函数,这些函数还支持并行化执行,下面这篇文章主要给大家介绍了关于Java Stream.reduce()用法的相关资料,需要的朋友可以参考下
2022-12-14

c_str()的用法详细解析

c_str()就是把string类对象转换成和c兼容的char *类型。这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式
2022-11-15

CStdioFile的用法详细解析

CStdioFile 不支持Duplicate,LockRange,和UnlockRange 这几个CFile 函数。如果在CStdioFile 中调用了这几个函数,将会出现CNoSupported 异常
2022-11-15

Java@GlobalLock注解详细分析讲解

这篇文章主要介绍了Java@GlobalLock注解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2022-11-21

pandaslocilocix用法详细分析

pandas处理数据时,我们会经常看到dataframe结构使用loc,iloc,ix等方法,那么这些方法到底有啥区别,下面我们来进行详细分析,感兴趣的朋友跟随小编一起看看吧
2023-01-09

STL list链表的用法详细解析

这篇文章是关于C++语言的一个新的扩展——标准模板库的(Standard Template Library),也叫STL
2022-11-15

Android Intent的几种用法详细解析

Intent应该算是Android中特有的东西。你可以在Intent中指定程序要执行的动作(比如:view,edit,dial),以及程序执行到该动作时所需要的资料。都指定好后,只要调用startActivity(),Android系统会自
2022-06-06

log4j使用详细解析

简单的说log4j就是帮助开发人员进行日志输出管理的API类库。它最重要的特点就可以配置文件灵活的设置日志信息的优先级、日志信息的输出目的地、日志信息的输出格式Log4j 除了可以记录程序运行日志信息外还有一重要的功能就是用来显示调试信息。
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录