Stream流reduce方法

在这里插入图片描述

reduce有三个重载方法。


Ⅰ,一个参数使用

在这里插入图片描述

Stream<Integer> iterate = Stream.iterate(1, (a) -> a + 2).limit(5);//1,3,5,7,9
System.out.println(iterate.reduce((a,b)->{
    	System.out.println("a: "+a);
    	System.out.println("b: "+b);
    	return a+b;
}).get());//25

在这里插入图片描述
第一次计算使用前两个参数,后面以上一次计算的返回值作为第一个参数,流中取下一个值作为第二个参数

Ⅱ,两个参数使用(带初始值)

在这里插入图片描述

Stream<Integer> iterate = Stream.iterate(1, (a) -> a + 2).limit(5);//1,3,5,7,9

System.out.println(iterate.reduce(10,(a,b)->{//这里的a和b都是Integer类型
            System.out.println("a: "+a);//a的值是上一次计算的返回值或者初始值
            System.out.println("b: "+b);//b的值是流中的值
            return a+b;//返回Integer类型,一定是Integer类型,与参数identity类型保持一致
}));//35

在这里插入图片描述

Ⅲ,三个参数使用(带初始值,并行计算,改变返回值类型)

在这里插入图片描述
说明下,第三个参数combiner翻译叫做“组合器”,第二个参数accumulator翻译为“累加器”,组合器只在并行流中起作用,否则不执行组合器的方法,可以使用parallel()方法将普通流转换为并行流,在普通流中调用三参数的reduce方法只起到改变返回值类型的作用。

所谓组合器就是把各个线程中得到的计算结果进行结合。


后两个参数他们的类型分别为BinaryOperator和BiFunction,而他们的关系如下:

interface BinaryOperator<T> extends BiFunction<T,T,T>

所以BinaryOperator就是一种BiFunction,这两个都是函数式接口,但是他们两个的不同之处在于泛型类型,BiFunction涉及到三种类型,而BinaryOperator仅一种;

@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u);//两个不同类型的参数返回另一个类型的值
}

因为BinaryOperator继承了BiFunction,除去各自提供的一些默认实现方法,我就可以把BinaryOperator看成如下定义:

//ps:这是我自己理解的,不是官方的代码
@FunctionalInterface
public interface BinaryOperator<T> {
    T apply(T t, T u);//两个同类型的参数返回同类型的值
}

回到reduce方法
在这里插入图片描述
这里就两种类型,U和T,T是流中的类型;U表示你想要得到不同于流中类型,那就传一个不同于T类型的初始变量
假如流中为Integer类型,想要一个String类型返回值可以这样

reduce(string,(string,int)->string,(string,string)->string);

1,演示非并行流返回值类型为流中类型

Stream<Integer> iterate = Stream.iterate(1, (a) -> a + 1).limit(5);//1,2,3,4,5
        System.out.println(iterate.reduce(0,(a,b)->{
            System.out.println(Thread.currentThread().getName()+"a: "+a);
            System.out.println(Thread.currentThread().getName()+"b: "+b);
            return a+b;
        },(c,d)->{
            System.out.println(Thread.currentThread().getName()+"c: "+c);
            System.out.println(Thread.currentThread().getName()+"d: "+d);
            return c+d;
        }));//15

在这里插入图片描述

可以看到打印并没有涉及到多线程并行(没有打印mainc或maind)。
2,演示非并行流返回类型不是流中类型

Stream<Integer> iterate = Stream.iterate(1, (a) -> a + 1).limit(5);//1,2,3,4,5
        System.out.println(iterate.reduce("",(a,b)->{
            System.out.println(a.getClass()+"   "+Thread.currentThread().getName()+"a: "+a);
            System.out.println(b.getClass()+"  "+Thread.currentThread().getName()+"b: "+b);
            return a+b;
        },(c,d)->{
            System.out.println(c.getClass()+"   "+Thread.currentThread().getName()+"c: "+c);
            System.out.println(d.getClass()+"   "+Thread.currentThread().getName()+"d: "+d);
            return c+d;
        }));//12345

在这里插入图片描述
从这里可以看出这里改变了a的类型为String,因为我传入了一个空字符串,且最后的结果为12345,第三个参数组合器仍然不起作用,因为这里使用的是普通流。
3,演示并行流返回类型是流中类型

Stream<Integer> iterate = Stream.iterate(1, (a) -> a + 1).limit(100);//1,2,3,4,5
        System.out.println(iterate.parallel().reduce(0,(a,b)->{
            System.out.println(Thread.currentThread().getName()+"a: "+a);
            System.out.println(Thread.currentThread().getName()+"b: "+b);
            return a+b;
        },(c,d)->{
            System.out.println(Thread.currentThread().getName()+"c: "+c);
            System.out.println(Thread.currentThread().getName()+"d: "+d);
            return c+d;
        }));//5050

在这里插入图片描述
可以看出创建了15条线程用于并行计算,转换为并行流后第三个参数方法才会执行
4,演示并行流返回类型不是流中类型

Stream<Integer> iterate = Stream.iterate(1, (a) -> a + 1).limit(5);//1,2,3,4,5
        System.out.println(iterate.parallel().reduce("",(a,b)->{
            System.out.println(a.getClass()+"   "+Thread.currentThread().getName()+"a: "+a);
            System.out.println(b.getClass()+"  "+Thread.currentThread().getName()+"b: "+b);
            return a+b;
        },(c,d)->{
            System.out.println(c.getClass()+"   "+Thread.currentThread().getName()+"c: "+c);
            System.out.println(d.getClass()+"   "+Thread.currentThread().getName()+"d: "+d);
            return c+d;
        }));//12345

在这里插入图片描述
在这里插入图片描述
可以看到只有b参数对应的位置数据类型为Integer,a,c,d都是String。
在我测试过程中还想要研究两个方法分别执行了多少次的时候,发现:流中有多少元素累加器就执行多少次,但是组合器的执行次数难以琢磨。
且最后的累加结果是很有规律的,并不是乱序。
在这里插入图片描述

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 8 中,Stream)提供了一种更加简便的方式来对集合进行操作。其中,reduce 方法就是中的一个重要方法,可以用于求和、求最大值、求最小值等。 reduce 方法有两个重载方法: 1. T reduce(T identity, BinaryOperator<T> accumulator) 这个方法接收一个初始值和一个二元运算符(BinaryOperator),返回一个计算结果。方法从初始值开始,将中的元素依次与初始值进行运算,并将每次运算的结果作为下一次运算的初始值,直到中的所有元素都运算完毕。 例如,下面的代码可以求一个整数列表的和: ``` List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); int sum = list.stream().reduce(0, Integer::sum); System.out.println(sum); // 输出 15 ``` 2. Optional<T> reduce(BinaryOperator<T> accumulator) 这个方法只接收一个二元运算符(BinaryOperator),返回一个 Optional 类型的计算结果。方法中的第一个元素开始,将每个元素依次与下一个元素进行运算,直到中的所有元素都运算完毕。 例如,下面的代码可以求一个整数列表中的最大值: ``` List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Optional<Integer> max = list.stream().reduce(Integer::max); System.out.println(max.get()); // 输出 5 ``` 需要注意的是,如果为空,reduce 方法会返回一个空的 Optional 对象。因此,在使用 reduce 方法时,应该先检查 Optional 对象是否为空,再进行操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值