当前位置: 首页 > 工具软件 > Reduce > 使用案例 >

java8 reduce 三个参数_JAVA8 Stream流之reduce()方法详解

范瀚昂
2023-12-01

JAVA8 Stream流之reduce()方法详解

reduce()简介

Reduce 原意:减少,缩小

根据指定的计算模型将Stream中的值计算得到一个最终结果

解释:reduce 操作可以实现从Stream中生成一个值,其生成的值不是随意的,而是根据指定的计算模型。比如,之前提到count、min和max方法,因为常用而被纳入标准库中。事实上,这些方法都是reduce操作。

reduce三个override的方法

reduce方法有三个override的方法:

Optionalreduce(BinaryOperatoraccumulator);

T reduce(T identity, BinaryOperatoraccumulator);

U reduce(U identity,BiFunction accumulator,BinaryOperator combiner);

公共集合

测试代码中的所有集合,都是该集合。

List javaProgrammers = new ArrayList() {

{

add(new Person("Elsdon", "Jaycob", "Java programmer", "male", 2000, 18));

add(new Person("Tamsen", "Brittany", "Java programmer", "female", 2371, 55));

add(new Person("Floyd", "Donny", "Java programmer", "male", 3322, 25));

add(new Person("Sindy", "Jonie", "Java programmer", "female", 35020, 15));

add(new Person("Vere", "Hervey", "Java programmer", "male", 2272, 25));

add(new Person("Maude", "Jaimie", "Java programmer", "female", 2057, 87));

add(new Person("Shawn", "Randall", "Java programmer", "male", 3120, 99));

add(new Person("Jayden", "Corrina", "Java programmer", "female", 345, 25));

add(new Person("Palmer", "Dene", "Java programmer", "male", 3375, 14));

add(new Person("Addison", "Pam", "Java programmer", "female", 3426, 20));

}

};

方式一reduce(BinaryOperatoraccumulator)

Optional reduce(BinaryOperator accumulator);

我们先看第一个变形,参数列表为一个函数接口BinaryOperator,

BinaryOperator源码:

public interface BinaryOperator extends BiFunction {

public static BinaryOperator minBy(Comparator super T> comparator) {

Objects.requireNonNull(comparator);

return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;

}

public static BinaryOperator maxBy(Comparator super T> comparator) {

Objects.requireNonNull(comparator);

return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;

}

}

看BinaryOperator接口源码,我们可以看到,它又继承了BiFunction.

另外,在BinaryOperator接口中又定义了另个静态方法为minBy和maxBy,

上面我们提到BinaryOperator接口继承了BiFunction,我们看一下BiFunction源码:

@FunctionalInterface

public interface BiFunction {

R apply(T t, U u);//接收两个参数 t 和 u, 返回 R

}

Bifunction中有一个apply方法,接收两个参数,返回一个结果

小结: 不管是BinaryOperator类还是最终继承的BiFunction类,在类上都有@FunctionalInterface注解,因此reduce(BinaryOperator accumulator)方法需要一个函数式接口参数,该函数式接口需要两个参数,返回一个结果(reduce中返回的结果会作为下次累加器计算的第一个参数),也就是累加器,最终得到一个Optional对象

测试示例代码:

@Test

public void Test() {

int asInt = javaProgrammers.stream()

.mapToInt(Person::getSalary)//返回数值流,减少拆箱封箱操作,避免占用内存 IntStream

.reduce((x, y) -> x += y)// int

.getAsInt(); //return int

System.out.printf("方式一 reduce(BinaryOperator accumulator) 求薪资测试结果:"+asInt);

/*解析:

1. reduce(BinaryOperator accumulator) reduce方法接受一个函数,这个函数有两个参数

2. 第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数

*注意:

1.第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素

2.方法返回值类型是Optional

*/

}

方式二reduce(T identity, BinaryOperatoraccumulator)

T reduce(T identity, BinaryOperator accumulator);

与第一种变形相同的是都会接受一个BinaryOperator函数接口,不同的是其会接受一个identity参数,identity参数与Stream中数据同类型,相当于一个的初始值,通过累加器accumulator迭代计算Stream中的数据,得到一个跟Stream中数据相同类型的最终结果。

测试示例代码:

@Test

public void test1(){

int reduce = javaProgrammers.stream().mapToInt(Person::getSalary).reduce(10000, (x, y) -> x += y);

System.out.printf("方式二 reduce(T identity, BinaryOperator accumulator) 求薪资测试结果:"+reduce);

/*注意:

* 1.与方式一相比设置了累加器的初始值,参数一(x)则不再是Stream中的第一个数据而是设置的初始值(10000)其他相同

*/

}

打印结果:

方式一 reduce(BinaryOperator accumulator) 求薪资测试结果:57308

方式二 reduce(T identity, BinaryOperator accumulator) 求薪资测试结果:67308 //初始值10000

方式三 reduce(U identity,BiFunction accumulator,BinaryOperator combiner)

\ U reduce(U identity,BiFunction\ accumulator,BinaryOperator\ combiner);

我们先观察分析再次被改变的参数列表:

\(~~~~~~~\) 1. 第一个参数:返回实例u,传递你要返回的U类型对象的初始化实例u

\(~~~~~~~\) 2. 第二个参数:累加器accumulator,可以使用lambda表达式,声明你在u上累加你的数据来源t的逻辑,例如(u,t)->u.sum(t),此时lambda表达式的行参列表是返回实例u和遍历的集合元素t,函数体是在u上累加t

\(~~~~~~~\) 3. 第三个参数:参数组合器combiner,接受lambda表达式。

根据参数我们一步一步分析代码示例:

@Test

public void test2() {

ArrayList accResult_ = Stream.of(1, 2, 3, 4)

//第一个参数,初始值为ArrayList

.reduce(new ArrayList(),

//第二个参数,实现了BiFunction函数式接口中apply方法,并且打印BiFunction

new BiFunction, Integer, ArrayList>() {

@Override

public ArrayList apply(ArrayList acc, Integer item) {

acc.add(item);

System.out.println("item: " + item);

System.out.println("acc+ : " + acc);

System.out.println("BiFunction");

return acc;

}

//第三个参数---参数的数据类型必须为返回数据类型,改参数主要用于合并多个线程的result值

// (Stream是支持并发操作的,为了避免竞争,对于reduce线程都会有独立的result)

}, new BinaryOperator>() {

@Override

public ArrayList apply(ArrayList acc, ArrayList item) {

System.out.println("BinaryOperator");

acc.addAll(item);

System.out.println("item: " + item);

System.out.println("acc+ : " + acc);

System.out.println("--------");

return acc;

}

});

System.out.println("accResult_: " + accResult_);

System.out.println("------------------lambda优化代码-----------------");

ArrayList newList = new ArrayList<>();

ArrayList accResult_s = Stream.of(1,2,3,4)

.reduce(newList,

(acc, item) -> {

acc.add(item);

System.out.println("item: " + item);

System.out.println("acc+ : " + acc);

System.out.println("BiFunction");

return acc;

}, (acc, item) -> null);

System.out.println("accResult_s: " + accResult_s);

}

\(~~~~\)示例代码中,第一个参数是ArrayList,在第二个函数参数中打印了“BiFunction”,而在第三个参数接口中打印了函数接口中打印了”BinaryOperator“.看下面的打印结果,只打印了“BiFunction”,而没有打印”BinaryOperator“,也就是说第三个函数参数并没有执行。分析参数时我们知道了该变形可以返回任意类型的数据。

\(~~~~\)对于第三个函数参数,为什么没有执行,而且其参数必须为返回的数据类型?这是因为Stream是支持并发操作的,为了避免竞争,对于reduce线程都会有独立的result,combiner的作用在于合并每个线程的result得到最终结果。这也说明了了第三个函数参数的数据类型必须为返回数据类型了。java8 reduce方法中的第三个参数combiner有什么作用?

打印结果:

item: 1

acc+ : [1]

BiFunction

item: 2

acc+ : [1, 2]

BiFunction

item: 3

acc+ : [1, 2, 3]

BiFunction

item: 4

acc+ : [1, 2, 3, 4]

BiFunction

另外需要注意:因为第三个参数用来处理并发操作,如何处理数据的重复性,应多做考虑,否则会出现重复数据!

结束语

路漫漫其修远行,吾将上下而求索

推荐参考博客:

https://blog.csdn.net/IO_Field/article/details/54971679

https://blog.csdn.net/weixin_43860260/article/details/94875064

 类似资料: