• 流API--缩减操作


    在Stream流操作中,比如说min(),max(),count()方法,这几个操作都会将一个流缩减成一个值,流API将这些操作称为特例缩减。另外,流API同时泛华了缩减这种概念,提供了reduce()方法,通过使用reduce()方法,可以基于任意条件,从流中返回一个值。根据定义,所有缩减操作都是终端操作。
    我们先来翻下api:
    Optional<T>	reduce(BinaryOperator<T> accumulator) :Performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any. 
    T 		reduce(T identity, BinaryOperator<T> accumulator) :Performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value. 
    <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. 

    先来看一段代码演示下如果对一个流做缩减操作:
    public static void main(String[] args) throws Exception
    	{
    		List<Integer> list = new ArrayList<>(4);
    		list.add(1);
    		list.add(2);
    		list.add(3);
    		list.add(4);
    		//reduce第一个重载,直接进行缩减
    		list.stream().reduce((a, b) -> a + b).ifPresent(System.out::println);
    		//reduce第二个重载,可以指定初始值,然后在进行缩减
    		System.out.println(list.stream().reduce(0, Integer::sum));
    		//reduce第三个重载,可以指定初始值,然后在进行缩减,第3个参数用来处理并行流的操作
    		System.out.println(list.stream().reduce(0, (a, b) -> a * 2 + b, (c, d) -> c + d));
    		List<String> list1 = Lists.newArrayList("1", "2", "3", "4");
    		System.out.println(list1.stream().reduce(1, (a, b) -> a + b.length(), (c, d) -> c + d));
    	}

    这里我们重点要看下前面2个方法:
    Optional<T> reduce(BinaryOperator<T> accumulator)
    T reduce(T identity, BinaryOperator<T> accumulator)
    第一个方法返回一个Optional对象,该对象包含了结果。第二个方法直接返回T类型的对象,这里的这个T类型就是流中元素的类型。在使用这2个方法的时候,要传入一个Lambda表达式,这个表达式要实现BinaryOperator<T>函数式接口,先说下这个接口吧:具体的可以去看我前面有篇博客的,这些函数式接口很容易忘掉了,我晕。
    public interface BinaryOperator<T> extends BiFunction<T,T,T> {}
    这个函数式接口扩展了BiFunction<T,T,T> 接口,这里只不过赋值方法的参数是同一个类型,然后返回值也是同一个类型而已。对于,BinaryOperator<T> 来说,apply方法现在变成了如下方法:
    T apply(T val, T value);其中val将包含前一个结果,然后value包含下一个元素。我们在调用reduce的时候,val将包含单位初始值或者第一个元素。在上面2个方法中,第一个方法将包含第一个元素,第二个方法将包含单位值。


    注意:
    累加器操作必须满足以下3个约束:
    1,无状态
    2,不干预
    3,结合性
    无状态意味着操作不依赖于任何状态信息,不干预意味着操作不会改变数据源,最后操作必须具有关联性。这里的关联性可以理解为加法结合律或者乘法结合律,举个例子,(a+b)+c=a+(b+c);


    最后这里整理下reduce的第3个重载方法:
    reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)。
    考虑如下情景:假设我们现在有一个包含多个对象的流,并且希望对他们的某个属性进行求和。例如求一个流中的所有字符串的总长度,这个时候我们没有办法用上面的2个reduce的重载,因为上面2个方法中需要一个(T,T)->T这样子的函数式接口,但是这里这2个类型是不同的,流中的元素是String的,但是累加的结果是整型的。对于这种情况,我们只能使用重载的第3个方法了。
    public static void main(String[] args)
    	{
    		Stream<String> of = Stream.of("张飞", "关羽");
    		//一下代码报错,类型不匹配The method reduce(String, BinaryOperator<String>) in the type Stream<String> 
    		//is not applicable for the arguments (int, BinaryOperator<String>)
    		of.reduce(0, (a, b) -> a + b.length());
    		System.out.println(of.reduce(0, (a, b) -> a + b.length(), Integer::sum));
    	}


  • 相关阅读:
    poj 1035 字符串匹配
    拓扑排序的小总结
    POJ1018
    POJ1328详细题解
    POJ1159题解报告
    POJ1088 (滑雪)
    树状树组区间修改,单点修改模板
    spfa模板
    树状树组离散化求逆序对模板
    POJ3723(最小生成树,负权)
  • 原文地址:https://www.cnblogs.com/LinkinPark/p/5232958.html
Copyright © 2020-2023  润新知