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 {
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 比較器。引用了多個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); }
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靜態工廠類來講,實現一共分爲兩種狀況:
經過CollectorImpl來實現。
經過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的代碼,就是咱們學習的範本。
講這麼細的緣由並非由於要本身去寫,是爲了瞭解內部是具體怎麼實現的。調用的時候就信心很是的足。