资讯专栏INFORMATION COLUMN

Stream流与Lambda表达式(二) Stream收集器 Collector接口

or0fun / 3455人阅读

摘要:一收集器接口陈杨收集器接口汇聚操作的元素类型即流中元素类型汇聚操作的可变累积类型汇聚操作的结果类型接口一种可变汇聚操作将输入元素累积到可变结果容器中在处理完所有输入元素后可以选择将累积的结果转换为最终表示可选操作归约操作

一、Stream收集器 Collector接口
package com.java.design.java8.Stream;

import com.java.design.java8.entity.Student;
import com.java.design.java8.entity.Students;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @author 陈杨
 */

@SpringBootTest
@RunWith(SpringRunner.class)
public class CollectorDetail {

    private List students;

    @Before
    public void init() {
        students=new Students().init();
    }

    @Test
    public void testCollectorDetail() {


        //     Collect 收集器 ---- Collector接口

        //     T-->汇聚操作的元素类型 即流中元素类型
        //     A-->汇聚操作的可变累积类型
        //     R-->汇聚操作的结果类型
        //     public interface Collector

        //     Collector接口   一种可变汇聚操作
        //                    将输入元素累积到可变结果容器中
        //                    在处理完所有输入元素后 可以选择将累积的结果转换为最终表示(可选操作)
        //                    归约操作支持串行与并行
        //     A  mutable reduction operation that  accumulates input elements into a mutable result container,
        //     optionally transforming  the accumulated result into a final representation after all input         elements
        //     have been processed.  Reduction operations can be performed either sequentially  or in parallel.


        //     Collectors 提供 Collector 汇聚实现  实际上是一个Collector工厂
        //     The class {@link Collectors}  provides implementations of many common mutable reductions.
二、Collector 接口组成
    //     Collector 由以下4个函数协同累积到容器 可选的执行最终转换
    //               supplier           创建一个新的结果容器
    //               accumulator累加器   将新数据元素合并到结果容器中
    //               combiner           合并结果容器  处理线程并发
    //               finisher           对容器执行可选的最终转换
    //
    //     A {@code Collector} is specified by four functions that work together to
    //     accumulate entries into a mutable result container, and optionally perform
    //     a final transform on the result.  They are:
    //           creation of a new result container ({@link #supplier()})
    //           incorporating a new data element into a result container ({@link #accumulator()})
    //           combining two result containers into one ({@link #combiner()})
    //           performing an optional final transform on the container ({@link #finisher()})
三、combiner
        /*
         *     A function that accepts two partial results and merges them.  The
         *     combiner function may fold state from one argument into the other and
         *     return that, or may return a new result container.
         *
         *
         *     BinaryOperator combiner();
         */

       /*     supplier创建单个结果容器-->accumulator调用累积功能-->partition结果--分区容器-->combiner合并分区容器

              A sequential implementation of a reduction using a collector would
              create a single result container using the supplier function, and invoke the
              accumulator function once for each input element.  A parallel implementation
              would partition the input, create a result container for each partition,
              accumulate the contents of each partition into a subresult for that partition,
              and then use the combiner function to merge the subresults into a combined
              result.
        */
四、identity associativity 约束
/*
       确保串行与并行结果的一致性,满足约束: identity  associativity
       To ensure that sequential and parallel executions produce equivalent
       results, the collector functions must satisfy an identity and an associativity constraints.
 */

/*     identity 约束:
       对于任何部分累积的结果, 将其与空结果容器组合必须生成等效的结果
       a == combiner.apply(a, supplier.get())

       The identity constraint says that for any partially accumulated result,
       combining it with an empty result container must produce an equivalent
       result.  That is, for a partially accumulated result {@code a} that is the
       result of any series of accumulator and combiner invocations, {@code a} must
       be equivalent to {@code combiner.apply(a, supplier.get())}.
 */

/*     associativity 约束:
       串行计算与并行拆分计算必须产生同等的结果

       The associativity constraint says that splitting the computation must
       produce an equivalent result.  That is, for any input elements {@code t1}
       and {@code t2}, the results {@code r1} and {@code r2} in the computation
       below must be equivalent:

         A a1 = supplier.get();
         accumulator.accept(a1, t1);
         accumulator.accept(a1, t2);
         R r1 = finisher.apply(a1);  // result without splitting

         A a2 = supplier.get();
         accumulator.accept(a2, t1);
         A a3 = supplier.get();
         accumulator.accept(a3, t2);
         R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting

 */
五、reduction 汇聚 的实现方式
        //      reduction 汇聚 的实现方式
        //      list.stream().reduce()                        对象不可变
        //      list.stream().collect(Collectors.reducing())  对象可变
        //      单线程可以实现结果一致 但在多线程中就会出现错误

        /*

                 Libraries that implement reduction based on {@code Collector}, such as
                 {@link Stream#collect(Collector)}, must adhere to the following constraints:


                 传递给accumulator的第一个参数,传递给combiner的二个参数,传递给finisher的参数
                 必须是函数(supplier accumulator combiner)上一次调用结果
                 理解: 参数类型A
                 Supplier supplier();
                 BiConsumer accumulator();
                 BinaryOperator combiner();
                 Function finisher();

                 The first argument passed to the accumulator function, both
                 arguments passed to the combiner function, and the argument passed to the
                 finisher function must be the result of a previous invocation of the
                 result supplier, accumulator, or combiner functions


                supplier accumulator combiner的实现结果-->
                传递给下一次supplier accumulator combiner操作
                或返还给汇聚操作的调用方
                而不进行其他操作
                The implementation should not do anything with the result of any of
                the result supplier, accumulator, or combiner functions other than to
                pass them again to the accumulator, combiner, or finisher functions,
                or return them to the caller of the reduction operation


                一个结果传递给combiner finisher而相同的对象没有从此函数中返回 这个结果不会再被使用
                这个传入结果是被消费了 生成了新的对象
                 If a result is passed to the combiner or finisher
                 function, and the same object is not returned from that function, it is
                 never used again


                一旦结果传递给combiner finisher 则不再会传递给accumulator
                说明流中元素已经传递完全  accumulator任务已执行完毕
                Once a result is passed to the combiner or finisher function, it
                is never passed to the accumulator function again

                非并发单线程
                For non-concurrent collectors, any result returned from the result
                supplier, accumulator, or combiner functions must be serially
                thread-confined.  This enables collection to occur in parallel without
                the {@code Collector} needing to implement any additional synchronization.
                The reduction implementation must manage that the input is properly
                partitioned, that partitions are processed in isolation, and combining
                happens only after accumulation is complete

                并发多线程
                For concurrent collectors, an implementation is free to (but not
                required to) implement reduction concurrently.  A concurrent reduction
                is one where the accumulator function is called concurrently from
                multiple threads, using the same concurrently-modifiable result container,
                rather than keeping the result isolated during accumulation.
                A concurrent reduction should only be applied if the collector has the
                {@link Characteristics#UNORDERED} characteristics or if the
                originating data is unordered

            */
六、Characteristics对Collectors的性能优化
            /*      Characteristics对Collectors的性能优化
             *
             *      Collectors also have a set of characteristics, that provide hints that can be used by a
             *      reduction implementation to provide better performance.
             *
             *
             *      Characteristics indicating properties of a {@code Collector}, which can
             *      be used to optimize reduction implementations.
             *
             *   enum Characteristics {
             *
                  * Indicates that this collector is concurrent, meaning that
                  * the result container can support the accumulator function being
                  * called concurrently with the same result container from multiple
                  * threads.
                  *
                  * If a {@code CONCURRENT} collector is not also {@code UNORDERED},
                  * then it should only be evaluated concurrently if applied to an
                  * unordered data source.

                 CONCURRENT, 多线程处理并发 一定要保证线程安全 使用无序数据源  与UNORDERED联合使用


                  * Indicates that the collection operation does not commit to preserving
                  * the encounter order of input elements.  (This might be true if the
                  * result container has no intrinsic order, such as a {@link Set}.)

                 UNORDERED,  无序集合


                  * Indicates that the finisher function is the identity function and
                  * can be elided.  If set, it must be the case that an unchecked cast
                  * from A to R will succeed.

                 IDENTITY_FINISH  强制类型转换
             }*/
七、Collector接口与 Collectors
        //     Collectors---> Collector接口简单实现  静态内部类CollectorImpl
        //     为什么要在Collectors类内部定义一个静态内部类CollectorImpl:
        //          Collectors是一个工厂、辅助类  方法的定义是静态的
        //          以类名直接调用方法的方式向developer提供最常见的Collector实现 其实现方式是CollectorImpl
        //          CollectorImpl类 有且仅有在 Collectors类 中使用 所以放在一起
八、测试方法:
        // Accumulate names into a List  将学生姓名累积成ArrayList集合
        List snameList = students.stream()
                .map(Student::getName).collect(Collectors.toList());
        System.out.println("将学生姓名累积成ArrayList集合:" + snameList.getClass());
        System.out.println(snameList);
        System.out.println("-----------------------------------------
");

        // Accumulate names into a TreeSet 将学生姓名累积成TreeSet集合
        Set snameTree = students.stream()
                .map(Student::getName).collect(Collectors.toCollection(TreeSet::new));



        System.out.println("将学生姓名累积成TreeSet集合:" + snameTree.getClass());
        System.out.println(snameTree);
        System.out.println("-----------------------------------------
");

        // Convert elements to strings and concatenate them, separated by commas  将学生姓名累积成一个Json串 以逗号分隔
        String joinedStudents = students.stream()
                .map(Student::toString).collect(Collectors.joining(","));
        System.out.println(" 将学生姓名累积成一个Json串 以逗号分隔:" + joinedStudents);
        System.out.println("-----------------------------------------
");

        // Compute sum of salaries of students  求学生总薪水
        double totalSalary = students.stream()
                .mapToDouble(Student::getSalary).sum();
        System.out.println("学生总薪水:" + totalSalary);
        System.out.println("-----------------------------------------
");


        // the min id of students     打印最小id的学生信息
        System.out.println("最小id的学生信息:");
        students.stream()
                .min(Comparator.comparingInt(Student::getId))
                .ifPresent(System.out::println);
        System.out.println("-----------------------------------------
");


        // the max id of students     打印最大id的学生信息
        System.out.println("最大id的学生信息:");
        students.stream()
                .max(Comparator.comparingInt(Student::getId))
                .ifPresent(System.out::println);
        System.out.println("-----------------------------------------
");


        // Compute avg of Age of students   求学生平均年龄
        Double avgAge = students.stream()
                .collect(Collectors.averagingInt(Student::getAge));
        System.out.println("学生平均年龄:" + avgAge);
        System.out.println("-----------------------------------------
");


        // Compute SummaryStatistics of Age of students   打印学生年龄的汇总信息
        IntSummaryStatistics ageSummaryStatistics = students.stream()
                .collect(Collectors.summarizingInt(Student::getAge));
        System.out.println("学生年龄的汇总信息:" + ageSummaryStatistics);
        System.out.println("-----------------------------------------
");


        //  根据性别分组 取id最小的学生
        //  直接使用Collectors.minBy返回的是Optional
        //  因能确认不为Null 使用Collectors.collectingAndThen-->Optional::get获取
        Map minIdStudent = students.stream().
                collect(Collectors.groupingBy(Student::getSex, Collectors.collectingAndThen
                        (Collectors.minBy(Comparator.comparingInt(Student::getId)), Optional::get)));

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

    }
}
九、测试结果
  .   ____          _            __ _ _
 / / ___"_ __ _ _(_)_ __  __ _    
( ( )\___ | "_ | "_| | "_ / _` |    
 /  ___)| |_)| | | | | || (_| |  ) ) ) )
  "  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.2.RELEASE)

2019-02-20 16:11:56.217  INFO 17260 --- [           main] c.j.design.java8.Stream.CollectorDetail  : Starting CollectorDetail on DESKTOP-87RMBG4 with PID 17260 (started by 46250 in E:IdeaProjectsdesign)
2019-02-20 16:11:56.223  INFO 17260 --- [           main] c.j.design.java8.Stream.CollectorDetail  : No active profile set, falling back to default profiles: default
2019-02-20 16:11:56.699  INFO 17260 --- [           main] c.j.design.java8.Stream.CollectorDetail  : Started CollectorDetail in 0.678 seconds (JVM running for 1.401)
-----------------------------------------

将学生姓名累积成ArrayList集合:class java.util.ArrayList
[Kirito, Asuna, Sinon, Yuuki, Alice]
-----------------------------------------

将学生姓名累积成TreeSet集合:class java.util.TreeSet
[Alice, Asuna, Kirito, Sinon, Yuuki]
-----------------------------------------

 将学生姓名累积成一个Json串 以逗号分隔:Student(id=1, name=Kirito, sex=Male, age=18, addr=Sword Art Online, salary=9.99999999E8),Student(id=2, name=Asuna, sex=Female, age=17, addr=Sword Art Online, salary=9.99999999E8),Student(id=3, name=Sinon, sex=Female, age=16, addr=Gun Gale Online, salary=9.99999999E8),Student(id=4, name=Yuuki, sex=Female, age=15, addr=Alfheim Online, salary=9.99999999E8),Student(id=5, name=Alice, sex=Female, age=14, addr=Alicization, salary=9.99999999E8)
-----------------------------------------

学生总薪水:4.999999995E9
-----------------------------------------

最小id的学生信息:
Student(id=1, name=Kirito, sex=Male, age=18, addr=Sword Art Online, salary=9.99999999E8)
-----------------------------------------

最大id的学生信息:
Student(id=5, name=Alice, sex=Female, age=14, addr=Alicization, salary=9.99999999E8)
-----------------------------------------

学生平均年龄:16.0
-----------------------------------------

学生年龄的汇总信息:IntSummaryStatistics{count=5, sum=80, min=14, average=16.000000, max=18}
-----------------------------------------

{Female=Student(id=2, name=Asuna, sex=Female, age=17, addr=Sword Art Online, salary=9.99999999E8), Male=Student(id=1, name=Kirito, sex=Male, age=18, addr=Sword Art Online, salary=9.99999999E8)}
-----------------------------------------

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73352.html

相关文章

  • Stream流与Lambda达式(四) 自定义集器

    摘要:一自定义收集器陈杨将集合转换为集合存放相同元素二自定义收集器陈杨将学生对象按照存放从中间容器数据类型转换为结果类型数据类型一致若不一致抛出类型转换异常对中间容器数据结果类型进行强制类型转换多个线程同时操作同一个容器并行多线 一、自定义SetCustomCollector收集器 package com.java.design.Stream.CustomCollector; impor...

    wind5o 评论0 收藏0
  • Stream流与Lambda达式(三) 静态工厂类Collectors

    摘要:陈杨一静态工厂类实现方式一静态工厂类实现方式静态工厂类最终由实现通过实现通过实现底层由实现是的一种具化表现形式使用拼接字符串二静态工厂类常用收集器二静态工厂类常用收集器返回一个不可修改的按照相遇的顺序返回一个不可修改的无序返回 /** * @author 陈杨 */ @SpringBootTest @RunWith(SpringRunner.class) public class...

    phodal 评论0 收藏0
  • Java8新特性总览

    摘要:新特性总览标签本文主要介绍的新特性,包括表达式方法引用流默认方法组合式异步编程新的时间,等等各个方面。还有对应的和类型的函数连接字符串广义的归约汇总起始值,映射方法,二元结合二元结合。使用并行流时要注意避免共享可变状态。 Java8新特性总览 标签: java [TOC] 本文主要介绍 Java 8 的新特性,包括 Lambda 表达式、方法引用、流(Stream API)、默认方...

    mayaohua 评论0 收藏0
  • Stream流与Lambda达式(一) 杂谈

    摘要:一流转换为数组集合陈杨将流转换为数组将流转换为数组将流转换为集合将流转换为集合解析 一、流 转换为数组、集合 package com.java.design.java8.Stream; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context...

    Harpsichord1207 评论0 收藏0
  • 《Java8实战》-第六章读书笔记(用流收集数据-01)

    摘要:收集器用作高级归约刚刚的结论又引出了优秀的函数式设计的另一个好处更易复合和重用。更具体地说,对流调用方法将对流中的元素触发一个归约操作由来参数化。另一个常见的返回单个值的归约操作是对流中对象的一个数值字段求和。 用流收集数据 我们在前一章中学到,流可以用类似于数据库的操作帮助你处理集合。你可以把Java 8的流看作花哨又懒惰的数据集迭代器。它们支持两种类型的操作:中间操作(如 filt...

    EscapedDog 评论0 收藏0

发表评论

0条评论

or0fun

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<