JAVA8Stream流之reduce()⽅法详解
JAVA8 Stream流之reduce()⽅法详解
reduce()简介
Reduce 原意:减少,缩⼩
根据指定的计算模型将Stream中的值计算得到⼀个最终结果
解释:reduce 操作可以实现从Stream中⽣成⼀个值,其⽣成的值不是随意的,⽽是根据指定的计算模型。⽐如,之前提到count、min和max⽅法,因为常⽤⽽被纳⼊标准库中。事实上,这些⽅法都是reduce操作。
reduce三个override的⽅法
reduce⽅法有三个override的⽅法:
Optional reduce(BinaryOperator accumulator);
T reduce(T identity, BinaryOperator accumulator);
<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner);
公共集合
测试代码中的所有集合,都是该集合。
List<Person> javaProgrammers = new ArrayList<Person>() {
{
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(BinaryOperator accumulator)
Optional<T> reduce(BinaryOperator<T> accumulator);
我们先看第⼀个变形,参数列表为⼀个函数接⼝BinaryOperator<T>,
BinaryOperator源码:
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
return (a, b) -> comparatorpare(a, b) <= 0 ? a : b;
}
public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
return (a, b) -> comparatorpare(a, b) >= 0 ? a : b;
}
}
看BinaryOperator接⼝源码,我们可以看到,它⼜继承了 BiFunction<T,T,T>.
另外,在BinaryOperator接⼝中⼜定义了另个静态⽅法为minBy和maxBy,
上⾯我们提到BinaryOperator接⼝继承了BiFunction<T,T,T>,我们看⼀下BiFunction<T,T,T>源码:
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);//接收两个参数 t 和 u, 返回 R
}
Bifunction中有⼀个apply⽅法,接收两个参数,返回⼀个结果
⼩结:不管是BinaryOperator类还是最终继承的BiFunction类,在类上都有@FunctionalInterface注解,因此reduce(BinaryOperator<T> 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<T> accumulator) 求薪资测试结果:"+asInt);
/*解析:
1. reduce(BinaryOperator<T> accumulator) reduce⽅法接受⼀个函数,这个函数有两个参数
2. 第⼀个参数是上次函数执⾏的返回值(也称为中间结果),第⼆个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执⾏这个函数的第⼀个参数 *注意:
1.第⼀次执⾏的时候第⼀个参数的值是Stream的第⼀个元素,第⼆个参数是Stream的第⼆个元素
2.⽅法返回值类型是Optional
*/
}
⽅式⼆reduce(T identity, BinaryOperator accumulator)
T reduce(T identity, BinaryOperator<T> accumulator);
与第⼀种变形相同的是都会接受⼀个BinaryOperator函数接⼝,不同的是其会接受⼀个identity参数,identity参数与Stream中数据同类型,相当于⼀个的初始值,通过累加器accumula tor迭代计算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<T> accumulator) 求薪资测试结果:"+re
duce);
/*注意:
* 1.与⽅式⼀相⽐设置了累加器的初始值,参数⼀(x)则不再是Stream中的第⼀个数据⽽是设置的初始值(10000)其他相同
*/
}
打印结果:
⽅式⼀ reduce(BinaryOperator<T> accumulator) 求薪资测试结果:57308
⽅式⼆ reduce(T identity, BinaryOperator<T> accumulator) 求薪资测试结果:67308 //初始值10000
⽅式三 reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner)
\<U\> U reduce(U identity,BiFunction\<U, ? super T, U\> accumulator,BinaryOperator\<U\> combiner);
我们先观察分析再次被改变的参数列表:
1. 第⼀个参数:返回实例u,传递你要返回的U类型对象的初始化实例u
Processing math: 100%
2. 第⼆个参数:累加器accumulator,可以使⽤lambda表达式,声明你在u上累加你的数据来源t的逻辑,例如(u,t)->u.sum(t),此时lambda表达式的⾏参列表是返回实例u和遍历的集合元素t,函数体是在u上累加t
3. 第三个参数:参数组合器combiner,接受lambda表达式。
根据参数我们⼀步⼀步分析代码⽰例:
@Test
public void test2() {
ArrayList<Integer> accResult_ = Stream.of(1, 2, 3, 4)
//第⼀个参数,初始值为ArrayList
.reduce(new ArrayList<Integer>(),
//第⼆个参数,实现了BiFunction函数式接⼝中apply⽅法,并且打印BiFunction
new BiFunction<ArrayList<Integer>, Integer, ArrayList<Integer>>() {
@Override
public ArrayList<Integer> apply(ArrayList<Integer> acc, Integer item) {
acc.add(item);
System.out.println("item: " + item);
java streamSystem.out.println("acc+ : " + acc);
System.out.println("BiFunction");
return acc;
}
/
/第三个参数---参数的数据类型必须为返回数据类型,改参数主要⽤于合并多个线程的result值
// (Stream是⽀持并发操作的,为了避免竞争,对于reduce线程都会有独⽴的result)
}, new BinaryOperator<ArrayList<Integer>>() {
@Override
public ArrayList<Integer> apply(ArrayList<Integer> acc, ArrayList<Integer> 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<Integer> newList = new ArrayList<>();
ArrayList<Integer> 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得到最终结果。这也说明了了第三个函数参数的数据类型必须为返回数据类型了。
打印结果:
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
另外需要注意:因为第三个参数⽤来处理并发操作,如何处理数据的重复性,应多做考虑,否则会出现重复数据!
结束语
路漫漫其修远⾏,吾将上下⽽求索
推荐参考博客:
blog.csdn/IO_Field/article/details/54971679
blog.csdn/weixin_43860260/article/details/94875064
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论