函数式编程 - java8中3个参数的reduce方法怎么理解?

查看:386
本文介绍了函数式编程 - java8中3个参数的reduce方法怎么理解?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

例如这个练习题,使用reduce和lambda表达式来实现map。
不明白的是reduce第三个参数的意义,感觉多此一举

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;

public class MapUsingReduce {
   
        public static <I, O> List<O> map(Stream<I> stream, Function<I, O> mapper) {
            return stream.reduce(new ArrayList<O>(), (acc, x) -> {
                // We are copying data from acc to new list instance. It is very inefficient,
                // but contract of Stream.reduce method requires that accumulator function does
                // not mutate its arguments.
                // Stream.collect method could be used to implement more efficient mutable reduction,
                // but this exercise asks to use reduce method.
                List<O> newAcc = new ArrayList<>(acc);
                newAcc.add(mapper.apply(x));
                return newAcc;
            }, (List<O> left, List<O> right) -> {
                // We are copying left to new list to avoid mutating it. 
                List<O> newLeft = new ArrayList<>(left);
                newLeft.addAll(right);
                return newLeft;
            });
        }
    
    }

下面是文档的说明,仍然不明白。。。

<U> U reduce(U identity,
              BiFunction<U,? super T,U> accumulator,
              BinaryOperator<U> combiner) 

Performs a reduction on the elements of this stream, using the provided identity, accumulation and combining functions. This is equivalent to:

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

but is not constrained to execute sequentially.

The identity value must be an identity for the combiner function. This means that for all u, combiner(identity, u) is equal to u. Additionally, the combiner function must be compatible with the accumulator function; for all u and t, the following must hold:

combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)

望指教,谢谢!

解决方案

我觉得可以这样理解

首先理解方法本身的意思:
Streamreduce方法,翻译过来是聚合或者是汇聚成一个的意思,由于Stream本身就代表着一堆数据,那stream.reduce()方法顾名思义就是把一堆数据聚合成一个数据

理解了reduce方法的意思,再来看看这个方法挂靠的对象是stream,是一个流,了解一下流的工作方式:
流底层核心其实是Spliterator接口的一个实现,而这个Spliterator接口其实本身就是Fork/Join并行框架的一个实现,所以归根结底要明白流的工作方式,就要明白一下Fork/Join框架的基本思想,即:以递归的方式将可以并行的任务拆分成更小的子任务,然后将每个子任务的结果合并起来生成整体的最后结果,画了个草图如下

理解了方法本身的意思以及流的工作方式,再结合到一起理解一下stream.reduce()方法,即用Fork/Join的方式把一堆数据聚合成一个数据,因此可以画出reduce方法的运行草图

结合草图,要实现stream.reduce()方法,必须要告诉JDK

  1. 你有什么需求数据要汇聚?(Stream已经提供了数据源,对应上面草图的A元素)

  2. 最后要汇聚成怎样的一个数据类型(对应reduce方法的参数一,对应上面草图的B元素)

  3. 如何将需求数据处理或转化成一个汇聚数据(对应reduce方法的参数二,对应上面草图的汇聚方式1)

  4. 如何将多个汇聚数据进行合并(对应reduce方法的参数三,对应上面草图的汇聚方式2)

再结合你给的map方法,其实是要把O类数据的流,最后转化为一个I类数据的List,因此按照上面的步骤可以进行对照

  1. 你有什么需求数据要汇聚?(O类数据流)

  2. 最后要汇聚成怎样的一个数据类型(一个集合,new ArrayList()

  3. 如何将需求数据处理或转化成一个汇聚数据(根据mapper把O转化为I,再用List.add方法)

  4. 如何将多个汇聚数据进行合并(两个集合合并,用List.addAll()

最后补充一点,若是你的参数真是Stream<I> streamFunction<I, O> mapper,建议不要用reduce方法,这么写可能会更好一点

public static <I, O> List<O> map(Stream<I> stream, Function<I, O> mapper) {
        return stream.map(mapper).collect(Collectors.toList());
    }

这篇关于函数式编程 - java8中3个参数的reduce方法怎么理解?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆