java8 汇聚操作之reduce、collect用法

java8 汇聚操作之reduce、collect用法

1. reduce

--reduce 操作可以实现从一组值中生成一个值。它有三个override的方法,我们一起来看看具体的实现。
  • Optional reduce(BinaryOperator accumulator);

    接受一个BinaryOperator类型的累加器,使用的lambda表达式为:
    
System.out.println(
                Stream.of(2,4,6,7,9,11)
                .reduce((sum , num) -> sum + num ) .get());

分析:可以看到reduce方法接受一个函数,这个函数有两个参数,第一个参数是上次函数执行的返回值(也称为中间结果),
第二个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数。
要注意的是:第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素
这个方法返回值类型是Optional,这是Java8防止出现NPE的一种可行方法。

  • T reduce(T identity, BinaryOperator accumulator);

     第二个方法跟第一个差不多,不过他接收一个初始,如果Stream为空,就直接返回该值。而且这个方法不会返回Optional,因为其不会出现null值。
    
System.out.println(
                Stream.of(2,4,6,7,9,11)
                .reduce(0 , (sum , num) -> sum + num )
                );
  • 《U》 U reduce(U identity,BiFunction《U》, ? super T, U》 accumulator,BinaryOperator《u》 combiner)

    第三个方法比第二个多了一个参数 BinaryOperator  combiner,这个是在并发执行的时候用的,用来把多个accumulator的结果结合到一起。
    
List<Integer> nums = new ArrayList<Integer>();
        nums.add(1);
        nums.add(2);
        nums.add(9);
        nums.add(7);
        nums.add(5);
        System.out.println(
                nums.parallelStream().reduce(0, (sum,num) -> sum + num , (result1 , result2) -> result1 + result2 ));

2. collect

  1. 《R, A》 R collect(Collector《? super T, A, R》 collector);

    我们看到collect()接收一个参数collector,这是一个收集器,一种通用的、从流生成复杂值的结构。只要将它传给collect 方法,所有的流就都可以使用它了。标准类库已经提供了一些有用的收集器,现在我们主要对java.util.stream.Collectors的几个方法进行讲解。
    

    1) 数据分块 partitioningBy

    如果你想把流分成两个集合,那么你可以用 Collectors.partitioningBy(Predicate predicate)。
    

收集器partitioningBy,它接受一个流,并将其分成两部分。它使用Predicate 对象判断一个元素应该属于哪个部分,并根据布尔值返回一个Map 到列表。因此,对于true List 中的元素,Predicate 返回true;对其他List 中的元素,Predicate 返回false。

*******  需求:把一群人中的未成年与成年人分出来。 *********

主要代码片段:
class Person{

    private String name;
    private int age;
    private String city;


    public boolean isTeenager(){
        if(age <= 18)
            return true;
        return false;
    }
    ...
}
案例实现:
        Person p1 = new Person("liMing", 21, "nc");
        Person p2 = new Person("liuHua", 14, "nc");
        Person p3 = new Person("zhangLiao", 25, "sz");
        Person p4 = new Person("zhuGang", 7, "sh");

        Map<Boolean, List<Person>>  lists = Stream.of(p1 , p2 , p3 ,p4 ).collect(Collectors.partitioningBy(person -> person.isTeenager()));

输出结果:
{true=[[name=liuHua, city=nc, age=14], [name=zhuGang, city=sh, age=7]], 
 false=[[name=liMing, city=nc, age=21], [name=zhangLiao, city=sz, age=25]]}
Collectors.partitioningBy(Predicate predicate ,Collector downstream )。这个重载方法是对predicate 后的数据进行二次处理。比如可以求未成年与成年人的数量:
Stream.of(p1 , p2 , p3 ,p4 ).collect(Collectors.partitioningBy(person -> person.isTeenager() , Collectors.counting()));         

2) 数据分组 groupingBy

数据分组是一种更自然的分割数据操作,与将数据分成ture 和false 两部分不同,可以使用任意值对数据分组。 
******* 需求:按照城市把人分组。***********

案例实现:
Map<String, List<Person>>  lists2 = Stream.of(p1 , p2 , p3 ,p4 ).collect(Collectors.groupingBy(person -> ((Person)person).getCity()));

输出:
{sh=[[name=zhuGang, city=sh, age=7]], 
 nc=[[name=liMing, city=nc, age=21], [name=liuHua, city=nc, age=14]], 
 sz=[[name=zhangLiao, city=sz, age=25]]}

附:两个参数的重载跟 partitioningBy一样,三个参数的是指定返回值的类型。
groupingByConcurrent是并行操作的时候用的,当不需要保证输出流的顺序的时候,可以用这个。

参考

1:Java 8 Lambdas book
2:Java 8 API doc
3:http://ifeve.com/stream/

    原文作者:KKKoko
    原文地址: https://blog.csdn.net/KKKoko/article/details/62043836
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞