2020了你還不會Java8新特性?(五)收集器比較器用法詳解及源碼剖析

收集器用法詳解與多級分組和分區

爲何在collectors類中定義一個靜態內部類?

static class CollectorImpl<T, A, R> implements Collector<T, A, R>

設計上,自己就是一個輔助類,是一個工廠。做用是給開發者提供常見的收集器實現。提供的方法都是靜態方法,能夠直接調用。java

函數式編程最大的特色:表示作什麼,而不是如何作。開發者更注重如作什麼,底層實現如何作。編程

/**
 * Implementations of {@link Collector} that implement various useful reduction
 * operations, such as accumulating elements into collections, summarizing
 * elements according to various criteria, etc.
 
   沒有實現的方法,能夠本身去編寫收集器。
   
 * <p>The following are examples of using the predefined collectors to perform
 * common mutable reduction tasks:
 * 舉例: 
 * <pre>{@code
 *     // Accumulate names into a List   名字加入到一個集合。
 *     List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
 *      
 *     // Accumulate names into a TreeSet  名字加入到一個Set。 待排序的集合。
 *     Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
 *
 *     // Convert elements to strings and concatenate them, separated by commas
 *     String joined = things.stream()
 *                           .map(Object::toString)
 *                           .collect(Collectors.joining(", "));
 *
 *     // Compute sum of salaries of employee      計算員工工資的總數。
 *     int total = employees.stream()
 *                          .collect(Collectors.summingInt(Employee::getSalary)));
 *
 *     // Group employees by department    對員工進行分組。
 *     Map<Department, List<Employee>> byDept
 *         = employees.stream()
 *                    .collect(Collectors.groupingBy(Employee::getDepartment));
 *
 *     // Compute sum of salaries by department    根據部門計算工資的總數。
 *     Map<Department, Integer> totalByDept
 *         = employees.stream()
 *                    .collect(Collectors.groupingBy(Employee::getDepartment,
 *                                                   Collectors.summingInt(Employee::getSalary)));
 *
 *     // Partition students into passing and failing    將學生進行分區。
 *     Map<Boolean, List<Student>> passingFailing =
 *         students.stream()
 *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
 *
 * }</pre>
 *
 * @since 1.8    提供了常見的方法。沒有的話能夠去自定義。
 */
public final class Collectors {

舉例。collector中的方法應用:

public static void main(String[] args) {
        Student student1 = new Student("zhangsan", 80);
        Student student2 = new Student("lisi", 90);
        Student student3 = new Student("wangwu", 100);
        Student student4 = new Student("zhaoliu", 90);
        Student student5 = new Student("zhaoliu", 90);

        List<Student> students = Arrays.asList(student1, student2, student3, student4, student5);

        //list 轉換成一個流,再轉換成一個集合.
        List<Student> students1 = students.stream().collect(Collectors.toList());
        students1.forEach(System.out::println);
        System.out.println("- - - - - - -");

        // collect 方法底層原理介紹.

        //有多種方法能夠實現同一個功能.什麼方式更好呢? 越具體的方法越好.   減小自動裝箱拆箱操做.
        System.out.println("count:" + students.stream().collect(Collectors.counting()));
        System.out.println("count:" + (Long) students.stream().count());
        System.out.println("- - - -  - - - -");

        //舉例練習
        //  找出集合中分數最低的學生,打印出來.
        students.stream().collect(minBy(Comparator.comparingInt(Student::getScore))).ifPresent(System.out::println);
        //  找出集合中分數最大成績
        students.stream().collect(maxBy(Comparator.comparingInt(Student::getScore))).ifPresent(System.out::println);
        //  求平均值
        System.out.println(students.stream().collect(averagingInt(Student::getScore)));
        //  求分數的綜合
        System.out.println(students.stream().collect(summingInt(Student::getScore)));
        //  求各類彙總信息  結果爲IntSummaryStatistics{count=5, sum=450, min=80, average=90.000000, max=100}
        System.out.println(students.stream().collect(summarizingInt(Student::getScore)));

        System.out.println(" - - - - - ");
        // 字符串的拼接   結果爲:zhangsanlisiwangwuzhaoliuzhaoliu
        System.out.println(students.stream().map(Student::getName).collect(joining()));
        //拼接加分隔符    結果爲:zhangsan,lisi,wangwu,zhaoliu,zhaoliu
        System.out.println(students.stream().map(Student::getName).collect(joining(",")));
        // 拼接加先後綴   結果爲:hello  zhangsan,lisi,wangwu,zhaoliu,zhaoliu  world
        System.out.println(students.stream().map(Student::getName).collect(joining(",", "hello  ", "  world")));

        System.out.println("- - - - - - ");
        // group by 多層分組
        // 根據分數和名字進行分組  輸出結果爲:
        // {80={zhangsan=[Student{name='zhangsan', score=80}]},
        // 100={wangwu=[Student{name='wangwu', score=100}]},
        // 90={lisi=[Student{name='lisi', score=90}], zhaoliu=[Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}]}}
        Map<Integer, Map<String, List<Student>>> collect = students.stream().collect(groupingBy(Student::getScore, groupingBy(Student::getName)));
        System.out.println(collect);

        System.out.println("- - - - - - - ");
        // partitioningBy   多級分區   輸出結果爲:{false=[Student{name='zhangsan', score=80}], true=[Student{name='lisi', score=90}, Student{name='wangwu', score=100}, Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}]}
        Map<Boolean, List<Student>> collect1 = students.stream().collect(partitioningBy(student -> student.getScore() > 80));
        System.out.println(collect1);
        // 按照大於80分區,再按照90分區
        //輸出結果爲:{false={false=[Student{name='zhangsan', score=80}], true=[]}, true={false=[Student{name='lisi', score=90}, Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}], true=[Student{name='wangwu', score=100}]}}
        Map<Boolean, Map<Boolean, List<Student>>> collect2 = students.stream().collect(partitioningBy(student -> student.getScore() > 80, partitioningBy(student -> student.getScore() > 90)));
        System.out.println(collect2);

        //分區, 而後求出每一個分組中的個數.    結果爲:{false=1, true=4}
        Map<Boolean, Long> collect3 = students.stream().collect(partitioningBy(student -> student.getScore() > 80, counting()));
        System.out.println(collect3);

        System.out.println("- - - - - - - ");
        //根據名字分組,獲得學生的分數     --, 使用collectingAndThen 求最小值,而後整合起來. 最後Optional.get()必定有值.
        students.stream().collect(groupingBy(Student::getName,collectingAndThen(minBy(Comparator.comparingInt(Student::getScore)), Optional::get)));
    }

Comparator比較器詳解與類型推斷特例

Comparator 比較器。引用了多個default方法。數組

完成一個功能時有多個方法,使用特化的方法。由於效率會更高。減小了裝箱拆箱的操做。減小性能損耗。多線程

舉例: 簡單功能實現

public static void main(String[] args) {
        List<String> list = Arrays.asList("nihao", "hello", "world", "welcome");

        //對list按照字母的升序排序
//        list.stream().sorted().forEach(System.out::println);

        //按照字符串的長度排序
//        Collections.sort(list, (item1, item2) -> item1.length() - item2.length());
//        Collections.sort(list, Comparator.comparingInt(String::length));

        //字符串的降序排序
//        list.sort(Comparator.comparingInt(String::length).reversed());

        // 下邊的形式會報錯   item識別成了(Obejct).
        //lambda表達式的類型推斷. 若是沒法推斷類型,須要本身制定類型
//        list.sort(Comparator.comparingInt(item-> item.length()).reversed());
        //這樣寫就成功了.
        list.sort(Comparator.comparingInt((String item )-> item.length()).reversed());

        //爲何這個地方沒法推斷類型?
        // 能推斷出的 :   list.stream()....    Strean<T>  傳遞的有參數.   精確的類型能夠進行類型推斷.
        //這個地方沒有明確具體是什麼類型.ToIntFunction<? super T>   .能夠是String 或者在往上的父類    這個地方當作了Object類了.

//        list.sort(Comparator.comparingInt((Boolean item)-> 1).reversed());
        //這種Boolean 就會報錯.編譯不經過.

        System.out.println(list);

    }

比較器深刻舉例練習

舉例:兩層的比較.先按照字符串的長度升序排序. 長度相同,根據每個ASCII碼的順序排序、

thenComparing()多級排序的練習。;併發

List<String> list = Arrays.asList("nihao", "hello", "world", "welcome");


//兩層的比較.先按照字符串的長度升序排序. 長度相同,根據每個ASCII碼的升序排序.     (不區分大小寫的 ,按照字母排序的規則)  幾種實現的方法。
    list.sort(Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER));

list.sort(Comparator.comparingInt(String::length).thenComparing((item1,item2) -> item1.toUpperCase().compareTo(item2.toUpperCase())));
       list.sort(Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toUpperCase)));

//排序後將順序翻轉過來. reverseOrder();
list.sort(Comparator.comparingInt(String::length).thenComparing(String::toLowerCase,Comparator.reverseOrder()));

// 按照字符串的長度降序排序, 再根據ASCII的降序排序
list.sort(Comparator.comparingInt(String::length).reversed()
                .thenComparing(String::toLowerCase,Comparator.reverseOrder()));

//多級排序
list.sort(Comparator.comparingInt(String::length).reversed()
                .thenComparing(String::toLowerCase, Comparator.reverseOrder())
                .thenComparing(Comparator.reverseOrder())); 
 // 最後一個thenComparing()沒有發生做用。

自定義一個簡單的收集器

jdk提供了Collector接口。app

public class MySetCollector<T>  implements Collector<T,Set<T>,Set<T>> {

    @Override
    public Supplier<Set<T>> supplier() {
        //用於提供一個空的容器
        System.out.println("supplier invoked! ");
        return HashSet::new;  // 不接受對象,返回一個Set對象
    }

    @Override
    public BiConsumer<Set<T>, T> accumulator() {
        // 累加器類型.   接收兩個參數不返回值.
        //完成的功能: 不斷的往set中添加元素
        System.out.println("accumulator invoked! ");
        return Set<T>::add ;
//        return HashSet<T>::add ;   返回HashSet報錯.  緣由: 返回的是中間類型的返回類型.  不論返回什麼類型的Set ,Set都符合要求.
    }

    @Override
    public BinaryOperator<Set<T>> combiner() {
        //將並行流的多個結果給合併起來.
        System.out.println("combiner invoked! ");
        return (set1,set2)->{
            set1.addAll(set2);
            return  set1;
        };
    }

    @Override
    public Function<Set<T>, Set<T>> finisher() {
        //完成器,把全部的結果都合併在一塊兒. 返回一個最終的結果類型
        //若是中間類型 和最終結果類型一致, 不執行此方法;
        System.out.println("finisher invoked! ");
//        return  t -> t ;
        return Function.identity(); // 老是返回參數.
    }

    @Override
    public Set<Characteristics> characteristics() {
        System.out.println("characterstics invoked! ");
        return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH,Characteristics.UNORDERED));  // 這個地方 不給參數,IDENTITY_FINISH  . 則會調用finisher()
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world");
        Set<String> collect = list.stream().collect(new MySetCollector<>());
        System.out.println(collect);
    }
  
  輸出結果爲: 
supplier invoked! 
accumulator invoked! 
combiner invoked! 
characterstics invoked! 
characterstics invoked! 
[world, hello]

}

接下來跟源碼,看一下程序的調用過程。ide

@Override
@SuppressWarnings("unchecked")
public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
    A container;
    if (isParallel()
            && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
            && (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) {
        container = collector.supplier().get();
        BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator();
        forEach(u -> accumulator.accept(container, u));
    }
    else {
        container = evaluate(ReduceOps.makeRef(collector));
    }
    return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
           ? (R) container
           : collector.finisher().apply(container);
}

自定義收集器的深度剖析與並行缺陷

// 舉例: 需求:將一個Set,進行一個收集.對結果進行加強,封裝在一個map當中.

// 輸入:Set<String>
// 輸出:Map<String,String>

// 示例輸入:   [hello,world,hello world]
// 示例輸出:  {[hello,hello],[world,world],[hello world,hello world]}
public class MySetCollector2<T> implements Collector<T, Set<T>, Map<T, T>> {
    @Override
    public Supplier<Set<T>> supplier() {
        System.out.println("supplier invoked!");
        return HashSet::new;
    }

    @Override
    public BiConsumer<Set<T>, T> accumulator() {
        System.out.println("accumlator invoked!");
        return (set, item) -> {
            set.add(item);
            //每次調用 打印出線程   這裏會打印6次,
            System.out.println("accunlator : " +set+ ", "+  Thread.currentThread().getName());
          
          //出現異常的緣由在這裏: 
// 一個線程去修改一個集合,同時另一個線程去迭代它(遍歷它)。程序就會拋出併發修改異常。若是是並行操做的話,就不要在操做中額外的添加操做。添加就添加,別再去打印他。 
        };
    }

    @Override
    public BinaryOperator<Set<T>> combiner() {
        System.out.println("combiner invoked!");
        //並行流的時候纔會被調用. 將並行流的多個結果給合併起來
        return (set1, set2) -> {
            set1.addAll(set2);
            return set2;
        };
    }

    @Override
    public Function<Set<T>, Map<T, T>> finisher() {
        System.out.println("finisher invoked!");
        // 中間類型和最終類型 同樣,這個是不會被調用的.
        //這裏不同 . 會進行調用

        return set -> {
            Map<T, T> map = new HashMap<>();
//            Map<T, T> map = new TreeMap<>();  直接返回一個排序的Map
            set.forEach(item -> map.put(item,item));
            return map;
        };
    }

    @Override
    public Set<Characteristics> characteristics() {
        System.out.println(" characteristics invoked");

        return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED));// 這個參數不能亂寫. 要理解每一個枚舉的具體意思.

//        return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED,Characteristics.CONCURRENT));// 這個參數不能亂寫. 要理解每一個枚舉的具體意思.
        //加了這個參數 Characteristics.CONCURRENT
        //  會出異常, 會正常運行.  Caused by: java.util.ConcurrentModificationException

//        return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED,Characteristics.IDENTITY_FINISH));
        // 加了參數Characteristics.IDENTITY_FINISH .  會報錯
        // Process 'command '/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1

        // IDENTITY_FINISH 實際的含義: 若是用和這個參數,表示 Finish函數就是 identity函數。 而且轉換必定要是成功的。失敗的話會拋異常.
        // 這個收集器具備什麼特性 ,由Characteristics 來定義. 就算你賦值的不實際,他也照樣執行.
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello","hello", "world", "helloworld","1","4","j");
        Set<String> set = new HashSet<>(list);

        System.out.println("set"+set);

//        Map<String, String> collect = set.stream().collect(new MySetCollector2<>());
        Map<String, String> collect = set.parallelStream().collect(new MySetCollector2<>());  //並行流
        System.out.println(collect);
    }
}

並行流缺陷詳解

並行: 
accumlator invoked!
accunlator : [j], main
accunlator : [j, hello], main
accunlator : [helloworld, 4, j, hello], ForkJoinPool.commonPool-worker-2
accunlator : [helloworld, 1, 4, j, hello], ForkJoinPool.commonPool-worker-2
accunlator : [helloworld, 1, world, 4, j, hello], ForkJoinPool.commonPool-worker-2
串行。
accunlator : [j], main
accunlator : [helloworld], ForkJoinPool.commonPool-worker-11
accunlator : [helloworld, 1], ForkJoinPool.commonPool-worker-11
accunlator : [helloworld, 1, world], ForkJoinPool.commonPool-worker-11
accunlator : [4], ForkJoinPool.commonPool-worker-9
accunlator : [j, hello], main
/**
     * Characteristics indicating properties of a {@code Collector}, which can
     * be used to optimize reduction implementations.
     */
    enum Characteristics {  // 特徵 
        /**
         * Indicates that this collector is <em>concurrent</em>, meaning that
         * the result container can support the accumulator function being
         * called concurrently with the same result container from multiple
         * threads.
         * 併發的,同一個結果容器能夠由多個線程同時調用。
         * <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED},
         * then it should only be evaluated concurrently if applied to an
         * unordered data source.
若是不是UNORDERED。只能用於無序的數據源。 
若是不加CONCURRENT,仍是能夠操做並行流。可是操做的不是一個結果容器,而是多個結果容器。則須要調用finisher.
若是加了CONCURRENT,則是多個線程操做同一結果容器。 則無需調用finisher.
         */  
        CONCURRENT,   

        /**
         * 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.
        若是用和這個參數,表示 Finish函數就是 identity函數。 而且轉換必定要是成功的。不會調用Finish方法
         */
        IDENTITY_FINISH
    }

出異常的根本緣由:

一個線程去修改一個集合,同時另一個線程去迭代它(遍歷它)。程序就會拋出併發修改異常。函數式編程

若是是並行操做的話,就不要在操做中額外的添加操做。添加就添加,別再去打印他。函數

若是不加CONCURRENT,仍是能夠操做並行流。可是操做的不是一個結果容器,而是多個結果容器。則須要調用finisher.
若是加了CONCURRENT,則是多個線程操做同一結果容器。 則無需調用finisher.性能

超線程介紹:

超線程(HT, Hyper-Threading)是英特爾研發的一種技術,於2002年發佈。超線程技術原先只應用於Xeon 處理器中,當時稱爲「Super-Threading」。以後陸續應用在Pentium 4 HT中。早期代號爲Jackson。 [1]

經過此技術,英特爾實如今一個實體CPU中,提供兩個邏輯線程。以後的Pentium D縱使不支持超線程技術,但就集成了兩個實體核心,因此仍會見到兩個線程。超線程的將來發展,是提高處理器的邏輯線程。英特爾於2016年發佈的Core i7-6950X即是將10核心的處理器,加上超線程技術,使之成爲20個邏輯線程的產品

收集器總結:

Collectors類中方法的實現練習。收集器老是有中間的容器。有必要的總結一下收集器中的方法。

當你具有一些前提的東西以後,你再去看難的東西就會以爲理所固然的。

對於Collectors靜態工廠類來講,實現一共分爲兩種狀況:

  1. 經過CollectorImpl來實現。

  2. 經過reducing方法來實現;reducing方法自己又是經過CollectorImpl實現的。

    總的來講,都是經過CollectorImpl來實現的。

1. toCollection(collectionFactory) 。  將集合轉成指定的集合。
public static <T, C extends Collection<T>>
Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
    return new CollectorImpl<>(collectionFactory, Collection<T>::add,
                               (r1, r2) -> { r1.addAll(r2); return r1; },
                               CH_ID);
}
2. toList()是 toCollection()方法的一種具體實現。
public static <T>
Collector<T, ?, List<T>> toList() {
    return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                               (left, right) -> { left.addAll(right); return left; },
                               CH_ID);
}
3. toSet() 是toCollection()方法的一種具體實現。
public static <T>
Collector<T, ?, Set<T>> toSet() {
    return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
                               (left, right) -> { left.addAll(right); return left; },
                               CH_UNORDERED_ID);
}
4. joining(); 融合成一個字符串。還有兩個重載的,單參數的和多參數的
public static Collector<CharSequence, ?, String> joining() {
    return new CollectorImpl<CharSequence, StringBuilder, String>(
            StringBuilder::new, StringBuilder::append,
            (r1, r2) -> { r1.append(r2); return r1; },
            StringBuilder::toString, CH_NOID);
}

public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
        return joining(delimiter, "", "");
    }

public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
                                                             CharSequence prefix,
                                                             CharSequence suffix) {
        return new CollectorImpl<>(
                () -> new StringJoiner(delimiter, prefix, suffix),
                StringJoiner::add, StringJoiner::merge,
                StringJoiner::toString, CH_NOID);
    }
5.mapping(); 將收集器的A 映射成B 
public static <T, U, A, R>
Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
                           Collector<? super U, A, R> downstream) {
    BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
    return new CollectorImpl<>(downstream.supplier(),
                               (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)),
                               downstream.combiner(), downstream.finisher(),
                               downstream.characteristics());
}

such as :
Map<City, Set<String>> lastNamesByCity
  = people.stream().collect(groupingBy(Person::getCity, mapping(Person::getLastName, toSet())));
6.collectingAndThen(); 收集處理轉換完後, 再去進行一個轉換。
public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
                                                            Function<R,RR> finisher) {
    Set<Collector.Characteristics> characteristics = downstream.characteristics();
    if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
        if (characteristics.size() == 1)
            characteristics = Collectors.CH_NOID;
        else {
            characteristics = EnumSet.copyOf(characteristics);
            characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
           // 這個地方爲何要把IDENTITY_FINISH 去掉。
          // 若是不去掉的話, 最終結果直接返回中間結果的類型
            characteristics = Collections.unmodifiableSet(characteristics);
        }
    }
    return new CollectorImpl<>(downstream.supplier(),
                               downstream.accumulator(),
                               downstream.combiner(),
                               downstream.finisher().andThen(finisher),
                               characteristics);
}

such as : 
 List<String> people
       = people.stream().collect(collectingAndThen(toList(),Collections::unmodifiableList));
7. counting(); 計數。
public static <T> Collector<T, ?, Long>
counting() {
    return reducing(0L, e -> 1L, Long::sum);
}
8. 最大值最小值  
    public static <T> Collector<T, ?, Optional<T>>
    minBy(Comparator<? super T> comparator) {
        return reducing(BinaryOperator.minBy(comparator));
    }
 public static <T> Collector<T, ?, Optional<T>>
    maxBy(Comparator<? super T> comparator) {
        return reducing(BinaryOperator.maxBy(comparator));
    }
9. summingInt();求和。
public static <T> Collector<T, ?, Integer>
summingInt(ToIntFunction<? super T> mapper) {
    return new CollectorImpl<>(
            () -> new int[1],   // 這個地方爲何不能夠用一個0,來當作中間類型呢?數字自己是一個值類型的,不可變的,無法引用。數組自己是一個引用類型,能夠進行傳遞。數組自己是一個容器。                                      
            (a, t) -> { a[0] += mapper.applyAsInt(t); },
            (a, b) -> { a[0] += b[0]; return a; },
            a -> a[0], CH_NOID);
}

public static <T> Collector<T, ?, Long>
    summingLong(ToLongFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new long[1],
                (a, t) -> { a[0] += mapper.applyAsLong(t); },
                (a, b) -> { a[0] += b[0]; return a; },
                a -> a[0], CH_NOID);
    }

public static <T> Collector<T, ?, Double>
    summingDouble(ToDoubleFunction<? super T> mapper) {
        /*
         * In the arrays allocated for the collect operation, index 0
         * holds the high-order bits of the running sum, index 1 holds
         * the low-order bits of the sum computed via compensated
         * summation, and index 2 holds the simple sum used to compute
         * the proper result if the stream contains infinite values of
         * the same sign.
         */
        return new CollectorImpl<>(
                () -> new double[3],  
                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t));
                            a[2] += mapper.applyAsDouble(t);},
                (a, b) -> { sumWithCompensation(a, b[0]);
                            a[2] += b[2];
                            return sumWithCompensation(a, b[1]); },
                a -> computeFinalSum(a),
                CH_NOID);
    }
10. averagingInt(); 求平均值。
public static <T> Collector<T, ?, Double>
averagingInt(ToIntFunction<? super T> mapper) {
    return new CollectorImpl<>(
            () -> new long[2],
            (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
            (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
            a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
}

public static <T> Collector<T, ?, Double>
    averagingLong(ToLongFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new long[2],
                (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; },
                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
    }
public static <T> Collector<T, ?, Double>
    averagingDouble(ToDoubleFunction<? super T> mapper) {
        /*
         * In the arrays allocated for the collect operation, index 0
         * holds the high-order bits of the running sum, index 1 holds
         * the low-order bits of the sum computed via compensated
         * summation, and index 2 holds the number of values seen.
         */
        return new CollectorImpl<>(
                () -> new double[4],
                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);},
                (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
                a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]),
                CH_NOID);
    }
11.  reducing() ; 詳解。
public static <T> Collector<T, ?, T>
    reducing(T identity, BinaryOperator<T> op) {
        return new CollectorImpl<>(
                boxSupplier(identity),
                (a, t) -> { a[0] = op.apply(a[0], t); },
                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
                a -> a[0],
                CH_NOID);
    }
12. groupingBy(); 分組方法詳解。
public static <T, K> Collector<T, ?, Map<K, List<T>>>   //使用者自己不注重中間類型怎麼操做。
groupingBy(Function<? super T, ? extends K> classifier) {  
    return groupingBy(classifier, toList());   //調用兩個參數的 groupingBy();
}

 * @param <T> the type of the input elements   //T; 接收的類型。
     * @param <K> the type of the keys  //  K,分類器函數中間返回結果的類型。
     * @param <A> the intermediate accumulation type of the downstream collector
     * @param <D> the result type of the downstream reduction
 *
public static <T, K, A, D>  
    Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
                                          Collector<? super T, A, D> downstream) {
        return groupingBy(classifier, HashMap::new, downstream); // 調用三參數的 groupingBy()
    }

//功能最徹底的groupingBy();

    /**
     * Returns a {@code Collector} implementing a cascaded "group by" operation
     * on input elements of type {@code T}, grouping elements according to a
     * classification function, and then performing a reduction operation on
     * the values associated with a given key using the specified downstream
     * {@code Collector}.  The {@code Map} produced by the Collector is created
     * with the supplied factory function.
     *
     * <p>The classification function maps elements to some key type {@code K}.
     * The downstream collector operates on elements of type {@code T} and
     * produces a result of type {@code D}. The resulting collector produces a
     * {@code Map<K, D>}.
     *
     * <p>For example, to compute the set of last names of people in each city,
     * where the city names are sorted:
     * <pre>{@code
     *     Map<City, Set<String>> namesByCity
     *         = people.stream().collect(groupingBy(Person::getCity, TreeMap::new,
     *                                              mapping(Person::getLastName, toSet())));
     * }</pre>
     *
     * @implNote
     * The returned {@code Collector} is not concurrent.  For parallel stream
     * pipelines, the {@code combiner} function operates by merging the keys
     * from one map into another, which can be an expensive operation.  If
     * preservation of the order in which elements are presented to the downstream
     * collector is not required, using {@link #groupingByConcurrent(Function, Supplier, Collector)}
     * may offer better parallel performance.
     *  返回的 並非併發的。若是順序並非很重要的話, 推薦使用groupingByConcurrent(); 併發的分組函數。
     * @param <T> the type of the input elements
     * @param <K> the type of the keys
     * @param <A> the intermediate accumulation type of the downstream collector
     * @param <D> the result type of the downstream reduction
     * @param <M> the type of the resulting {@code Map}
     * @param classifier a classifier function mapping input elements to keys
     * @param downstream a {@code Collector} implementing the downstream reduction
     * @param mapFactory a function which, when called, produces a new empty
     *                   {@code Map} of the desired type
     * @return a {@code Collector} implementing the cascaded group-by operation
     *
     * @see #groupingBy(Function, Collector)
     * @see #groupingBy(Function)
     * @see #groupingByConcurrent(Function, Supplier, Collector)
     */
public static <T, K, D, A, M extends Map<K, D>>  
    Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
                                  Supplier<M> mapFactory,
                                  Collector<? super T, A, D> downstream) {
        Supplier<A> downstreamSupplier = downstream.supplier();
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
            K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
            A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
            downstreamAccumulator.accept(container, t); 
        };
        BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());  //接收兩個參數,參會一個結果。
        @SuppressWarnings("unchecked")
        Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory; // 進行一個強制的類型轉換。

        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {       
         //若是 IDENTITY_FINISH , 則不用調用finisher方法。
           return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
        }
        else {
            @SuppressWarnings("unchecked")
            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
            Function<Map<K, A>, M> finisher = intermediate -> {
                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
                @SuppressWarnings("unchecked")
                M castResult = (M) intermediate;
                return castResult;
            };
            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
        }
    }
13. groupingByConcurrent(); 併發的分組方法。 使用前提是對數據裏邊的順序沒有要求。
   /**
     * Returns a concurrent {@code Collector} implementing a cascaded "group by"
     * operation on input elements of type {@code T}, grouping elements
     * according to a classification function, and then performing a reduction
     * operation on the values associated with a given key using the specified
     * downstream {@code Collector}.
     */         //  ConcurrentHashMap    是一個支持併發的Map 
  public static <T, K>
    Collector<T, ?, ConcurrentMap<K, List<T>>>
    groupingByConcurrent(Function<? super T, ? extends K> classifier) {
        return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList());
    }

 public static <T, K, A, D>
    Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier,
                                                              Collector<? super T, A, D> downstream) {
        return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream);
    }

 public static <T, K, A, D, M extends ConcurrentMap<K, D>>
    Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
                                            Supplier<M> mapFactory,
                                            Collector<? super T, A, D> downstream) {
        Supplier<A> downstreamSupplier = downstream.supplier();
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BinaryOperator<ConcurrentMap<K, A>> merger = Collectors.<K, A, ConcurrentMap<K, A>>mapMerger(downstream.combiner());
        @SuppressWarnings("unchecked")
        Supplier<ConcurrentMap<K, A>> mangledFactory = (Supplier<ConcurrentMap<K, A>>) mapFactory;
        BiConsumer<ConcurrentMap<K, A>, T> accumulator;
        if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) {
            accumulator = (m, t) -> {
                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
                A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
                downstreamAccumulator.accept(resultContainer, t);
            };
        }
        else {
            accumulator = (m, t) -> {
                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
                A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
                synchronized (resultContainer) {  // 這裏有一個同步的操做。雖然是多線程操做同一容器,可是同時仍是隻有一個線程操做,進行了同步。
                    downstreamAccumulator.accept(resultContainer, t);
                }
            };
        }

        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_CONCURRENT_ID);
        }
        else {
            @SuppressWarnings("unchecked")
            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
            Function<ConcurrentMap<K, A>, M> finisher = intermediate -> {
                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
                @SuppressWarnings("unchecked")
                M castResult = (M) intermediate;
                return castResult;
            };
            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_CONCURRENT_NOID);
        }
    }
14. partitioningBy(); 分區詳解。
public static <T>
Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
    return partitioningBy(predicate, toList());
}

public static <T, D, A>
    Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
                                                    Collector<? super T, A, D> downstream) {
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BiConsumer<Partition<A>, T> accumulator = (result, t) ->
                downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
        BinaryOperator<A> op = downstream.combiner();
        BinaryOperator<Partition<A>> merger = (left, right) ->
                new Partition<>(op.apply(left.forTrue, right.forTrue),
                                op.apply(left.forFalse, right.forFalse));
        Supplier<Partition<A>> supplier = () ->
                new Partition<>(downstream.supplier().get(),
                                downstream.supplier().get());
        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
            return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
        }
        else {
            Function<Partition<A>, Map<Boolean, D>> finisher = par ->
                    new Partition<>(downstream.finisher().apply(par.forTrue),
                                    downstream.finisher().apply(par.forFalse));
            return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
        }
    }

jdk的代碼,就是咱們學習的範本。

講這麼細的緣由並非由於要本身去寫,是爲了瞭解內部是具體怎麼實現的。調用的時候就信心很是的足。

附一個小插曲。

image-20200105201926874

相關文章
相關標籤/搜索