自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java12 Collectors.teeing你真的需要了解一下

開發(fā) 后端
在 Java 12 里面有個非常好用但在官方 JEP 沒有公布的功能,因為它只是 Collector 中的一個小改動,它的作用是 merge 兩個 collector 的結果。

前言

在 Java 12 里面有個非常好用但在官方 JEP 沒有公布的功能,因為它只是 Collector 中的一個小改動,它的作用是 merge 兩個 collector 的結果,這句話顯得很抽象,老規(guī)矩,我們先來看個圖:

管道改造經常會用這個小東西,通常我們叫它「三通」,它的主要作用就是將 downstream1 和 downstream2 的流入合并,然后從 merger 流出

有了這個形象的說明我們就進入正題吧

Collectors.teeing

上面提到的小功能就是 Collectors.teeing API, 先來看一下 JDK 關于該 API 的說明,看著覺得難受的直接忽略,繼續(xù)向下看例子就好了: 

  1. /**  
  2.  * Returns a {@code Collector} that is a composite of two downstream collectors.  
  3.  * Every element passed to the resulting collector is processed by both downstream  
  4.  * collectors, then their results are merged using the specified merge function  
  5.  * into the final result.  
  6.  *  
  7.  * <p>The resulting collector functions do the following:  
  8.  *  
  9.  * <ul>  
  10.  * <li>supplier: creates a result container that contains result containers  
  11.  * obtained by calling each collector's supplier  
  12.  * <li>accumulator: calls each collector's accumulator with its result container  
  13.  * and the input element  
  14.  * <li>combiner: calls each collector's combiner with two result containers  
  15.  * <li>finisher: calls each collector's finisher with its result container,  
  16.  * then calls the supplied merger and returns its result.  
  17.  * </ul>  
  18.  *  
  19.  * <p>The resulting collector is {@link Collector.Characteristics#UNORDERED} if both downstream  
  20.  * collectors are unordered and {@link Collector.Characteristics#CONCURRENT} if both downstream  
  21.  * collectors are concurrent.  
  22.  *  
  23.  * @param <T>         the type of the input elements  
  24.  * @param <R1>        the result type of the first collector  
  25.  * @param <R2>        the result type of the second collector  
  26.  * @param <R>         the final result type  
  27.  * @param downstream1 the first downstream collector  
  28.  * @param downstream2 the second downstream collector  
  29.  * @param merger      the function which merges two results into the single one  
  30.  * @return a {@code Collector} which aggregates the results of two supplied collectors.  
  31.  * @since 12  
  32.  */  
  33. public static <T, R1, R2, R>  
  34. Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,  
  35.                           Collector<? super T, ?, R2> downstream2,  
  36.                           BiFunction<? super R1, ? super R2, R> merger) {  
  37.     return teeing0(downstream1, downstream2, merger);  

API 描述重的一句話非常關鍵: 

Every element passed to the resulting collector is processed by both downstream collectors

結合「三通圖」來說明就是,集合中每一個要被傳入 merger 的元素都會經過 downstream1 和 downstream2 的加工處理

其中 merger 類型是 BiFunction,也就是說接收兩個參數(shù),并輸出一個值,請看它的 apply 方法 

  1. @FunctionalInterface  
  2. public interface BiFunction<T, U, R> {  
  3.     /**  
  4.      * Applies this function to the given arguments.  
  5.      *  
  6.      * @param t the first function argument  
  7.      * @param u the second function argument  
  8.      * @return the function result  
  9.      */  
  10.     R apply(T t, U u);  

至于可以如何處理,我們來看一些例子吧

例子

為了更好的說明 teeing 的使用,列舉了四個例子,看過這四個例子再回看上面的 API 說明,相信你會柳暗花明了

計數(shù)和累加

先來看一個經典的問題,給定的數(shù)字集合,需要映射整數(shù)流中的元素數(shù)量和它們的和 

  1. class CountSum {  
  2.     private final Long count;  
  3.     private final Integer sum;  
  4.     public CountSum(Long count, Integer sum) {  
  5.         this.count = count; 
  6.          this.sum = sum;  
  7.     }  
  8.     @Override  
  9.     public String toString() {  
  10.         return "CountSum{" +  
  11.                 "count=" + count +  
  12.                 ", sum=" + sum +  
  13.                 '}';  
  14.     }  

通過 Collectors.teeing 處理 

  1. CountSum countsum = Stream.of(2, 11, 1, 5, 7, 8, 12)  
  2.         .collect(Collectors.teeing(  
  3.                 counting(),  
  4.                 summingInt(e -> e),  
  5.                 CountSum::new));  
  6. System.out.println(countsum.toString()); 
  •  downstream1 通過 Collectors 的靜態(tài)方法 counting 進行集合計數(shù)
  •  downstream2 通過 Collectors 的靜態(tài)方法 summingInt 進行集合元素值的累加
  •  merger 通過 CountSum 構造器收集結果

運行結果: 

  1. CountSum{count=7sum=46

我們通過 teeing 一次性得到我們想要的結果,繼續(xù)向下看其他例子:

最大值與最小值

通過給定的集合, 一次性計算出集合的最大值與最小值,同樣新建一個類 MinMax,并創(chuàng)建構造器用于 merger 收集結果 

  1. class MinMax {  
  2.     private final Integer min;  
  3.     private final Integer max;  
  4.     public MinMax(Integer min, Integer max) {  
  5.         this.min = min;  
  6.         this.max = max;  
  7.     }  
  8.     @Override  
  9.     public String toString() {  
  10.         return "MinMax{" +  
  11.                 "min=" + min +  
  12.                 ", max=" + max +  
  13.                 '}';  
  14.     }  

通過 teeing API 計算結果: 

  1. MinMax minmax = Stream.of(2, 11, 1, 5, 7, 8, 12)  
  2.         .collect(Collectors.teeing(  
  3.                 minBy(Comparator.naturalOrder()),  
  4.                 maxBy(Comparator.naturalOrder()),  
  5.                 (Optional<Integer> a, Optional<Integer> b) -> new MinMax(a.orElse(Integer.MIN_VALUE), b.orElse(Integer.MAX_VALUE))));  
  6. System.out.println(minmax.toString()); 
  •  downstream1 通過 Collectors 的靜態(tài)方法 minBy,通過 Comparator 比較器按照自然排序找到最小值
  •  downstream2 通過 Collectors 的靜態(tài)方法 maxBy,通過 Comparator 比較器按照自然排序找到最大值
  •  merger 通過 MinMax 構造器收集結果,只不過為了應對 NPE,將 BiFunction 的兩個入?yún)⒔涍^ Optional 處理

運行結果:   

  1. MinMax{min=1max=12

為了驗證一下 Optional,我們將集合中添加一個 null 元素,并修改一下排序規(guī)則來看一下排序結果: 

  1. MinMax minmax = Stream.of(null, 2, 11, 1, 5, 7, 8, 12)  
  2.                 .collect(Collectors.teeing(  
  3.                         minBy(Comparator.nullsFirst(Comparator.naturalOrder())),  
  4.                         maxBy(Comparator.nullsLast(Comparator.naturalOrder())),  
  5.                         (Optional<Integer> a, Optional<Integer> b) -> new MinMax(a.orElse(Integer.MIN_VALUE), b.orElse(Integer.MAX_VALUE)))); 
  •  downstream1 處理規(guī)則是將 null 放在排序的最前面
  •  downstream2 處理規(guī)則是將 null 放在排序的最后面
  •  merger 處理時,都會執(zhí)行 optional.orElse 方法,分別輸出最小值與最大值

運行結果:   

  1. MinMax{min=-2147483648, max=2147483647

瓜的總重和單個重量

接下來舉一個更貼合實際的操作對象的例子 

  1. // 定義瓜的類型和重量  
  2. class Melon {  
  3.     private final String type;  
  4.     private final int weight;  
  5.     public Melon(String type, int weight) {  
  6.         this.type = type;  
  7.         this.weight = weight;  
  8.     }  
  9.     public String getType() {  
  10.         return type;  
  11.     }  
  12.     public int getWeight() {  
  13.         return weight;  
  14.     }  
  15.  
  16. // 總重和單個重量列表  
  17. class WeightsAndTotal {  
  18.     private final int totalWeight;  
  19.     private final List<Integer> weights;  
  20.     public WeightsAndTotal(int totalWeight, List<Integer> weights) {  
  21.         this.totalWeight = totalWeight;  
  22.         this.weights = weights;  
  23.     }  
  24.     @Override  
  25.     public String toString() {  
  26.         return "WeightsAndTotal{" +  
  27.                 "totalWeight=" + totalWeight +  
  28.                 ", weights=" + weights +  
  29.                 '}';  
  30.     }  

通過 teeing API 計算總重量和單個列表重量 

  1. List<Melon> melons = Arrays.asList(new Melon("Crenshaw", 1200),  
  2.     new Melon("Gac", 3000), new Melon("Hemi", 2600),  
  3.     new Melon("Hemi", 1600), new Melon("Gac", 1200),  
  4.     new Melon("Apollo", 2600), new Melon("Horned", 1700),  
  5.     new Melon("Gac", 3000), new Melon("Hemi", 2600)  
  6. );  
  7. WeightsAndTotal weightsAndTotal = melons.stream()  
  8.     .collect(Collectors.teeing(  
  9.             summingInt(Melon::getWeight),  
  10.             mapping(m -> m.getWeight(), toList()),  
  11.             WeightsAndTotal::new));  
  12. System.out.println(weightsAndTotal.toString()); 
  •  downstream1 通過 Collectors 的靜態(tài)方法 summingInt 做重量累加
  •  downstream2 通過 Collectors 的靜態(tài)方法 mapping 提取出瓜的重量,并通過流的終結操作 toList() 獲取結果
  •  merger 通過 WeightsAndTotal 構造器獲取結果

運行結果:   

  1. WeightsAndTotal{totalWeight=19500weights=[1200, 3000, 2600, 1600, 1200, 2600, 1700, 3000, 2600]} 

繼續(xù)一個更貼合實際的例子吧:

預約人員列表和預約人數(shù) 

  1. class Guest {  
  2.     private String name;  
  3.     private boolean participating;  
  4.     private Integer participantsNumber;  
  5.     public Guest(String name, boolean participating, Integer participantsNumber) {  
  6.         this.name = name;  
  7.         this.participating = participating;  
  8.         this.participantsNumber = participantsNumber;  
  9.     }  
  10.     public boolean isParticipating() {  
  11.         return participating;  
  12.     }  
  13.     public Integer getParticipantsNumber() {  
  14.         return participantsNumber;  
  15.     }  
  16.     public String getName() {  
  17.         return name;  
  18.     }  
  19.  
  20. class EventParticipation {  
  21.     private List<String> guestNameList;  
  22.     private Integer totalNumberOfParticipants;  
  23.     public EventParticipation(List<String> guestNameList, Integer totalNumberOfParticipants) {  
  24.         this.guestNameList = guestNameList;  
  25.         this.totalNumberOfParticipants = totalNumberOfParticipants; 
  26.     }  
  27.     @Override  
  28.     public String toString() {  
  29.         return "EventParticipation { " +  
  30.                 "guests = " + guestNameList +  
  31.                 ", total number of participants = " + totalNumberOfParticipants +  
  32.                 " }";  
  33.     }  

通過 teeing API 處理 

  1. var result = Stream.of(  
  2.                 new Guest("Marco", true, 3),  
  3.                 new Guest("David", false, 2),  
  4.                 new Guest("Roger",true, 6))  
  5.                 .collect(Collectors.teeing(  
  6.                         Collectors.filtering(Guest::isParticipating, Collectors.mapping(Guest::getName, Collectors.toList())),  
  7.                         Collectors.summingInt(Guest::getParticipantsNumber),  
  8.                         EventParticipation::new  
  9.                 ));  
  10. System.out.println(result); 
  •  downstream1 通過 filtering 方法過濾出確定參加的人,并 mapping 出他們的姓名,最終放到 toList 集合中
  •  downstream2 通過 summingInt 方法計數(shù)累加
  •  merger 通過 EventParticipation 構造器收集結果

其中我們定義了 var result 來收集結果,并沒有指定類型,這個語法糖也加速了我們編程的效率

運行結果:   

  1. EventParticipation { guests = [Marco, Roger], total number of participants = 11 } 

總結

其實 teeing API 就是靈活應用 Collectors 里面定義的靜態(tài)方法,將集合元素通過 downstream1 和 downstream2 進行處理,最終通過 merger 收集起來,當項目中有同時獲取兩個收集結果時,是時候應用我們的 teeing API 了。 

 

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2015-12-23 10:00:04

多種編程語言

2021-07-06 14:56:20

深度學習編程人工智能

2021-05-19 09:40:14

Android 12Android

2024-01-31 13:02:00

高并發(fā)熱點散列庫存分桶

2012-06-27 09:11:47

2022-08-25 14:42:45

JavaScrip字符串

2012-06-26 10:13:55

2011-04-01 11:16:06

hessian

2017-09-22 14:12:33

Android字體 Typeface

2021-08-09 14:40:02

物聯(lián)網IOT智能家居

2017-11-16 18:48:48

Hadoop數(shù)據(jù)庫數(shù)據(jù)處理

2016-11-01 16:41:08

直通網線連接端口傳輸數(shù)據(jù)

2018-04-02 14:21:43

互聯(lián)網物聯(lián)網

2023-05-28 18:21:32

2022-03-24 13:36:18

Java悲觀鎖樂觀鎖

2017-12-18 15:33:56

Java基礎編程

2022-07-29 09:17:46

JavaScriptReactJS學習

2022-10-27 10:29:15

2022-10-26 07:21:15

網絡視頻開發(fā)

2015-09-17 09:36:46

Chrome改變
點贊
收藏

51CTO技術棧公眾號