中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java12 Collectors.teeing如何理解

發布時間:2022-01-06 21:29:07 來源:億速云 閱讀:162 作者:柒染 欄目:編程語言

Java12 Collectors.teeing如何理解,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

前言

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

Java12 Collectors.teeing如何理解

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

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

Collectors.teeing

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

/**   * Returns a {@code Collector} that is a composite of two downstream collectors.   * Every element passed to the resulting collector is processed by both downstream   * collectors, then their results are merged using the specified merge function   * into the final result.   *   * <p>The resulting collector functions do the following:   *   * <ul>   * <li>supplier: creates a result container that contains result containers   * obtained by calling each collector's supplier   * <li>accumulator: calls each collector's accumulator with its result container   * and the input element   * <li>combiner: calls each collector's combiner with two result containers   * <li>finisher: calls each collector's finisher with its result container,   * then calls the supplied merger and returns its result.   * </ul>   *   * <p>The resulting collector is {@link Collector.Characteristics#UNORDERED} if both downstream   * collectors are unordered and {@link Collector.Characteristics#CONCURRENT} if both downstream   * collectors are concurrent.   *   * @param <T>         the type of the input elements   * @param <R1>        the result type of the first collector   * @param <R2>        the result type of the second collector   * @param <R>         the final result type   * @param downstream1 the first downstream collector   * @param downstream2 the second downstream collector   * @param merger      the function which merges two results into the single one   * @return a {@code Collector} which aggregates the results of two supplied collectors.   * @since 12   */  public static <T, R1, R2, R>  Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,                            Collector<? super T, ?, R2> downstream2,                            BiFunction<? super R1, ? super R2, R> merger) {      return teeing0(downstream1, downstream2, merger);  }

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

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

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

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

@FunctionalInterface  public interface BiFunction<T, U, R> {      /**       * Applies this function to the given arguments.       *       * @param t the first function argument       * @param u the second function argument       * @return the function result       */      R apply(T t, U u);  }

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

例子

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

計數和累加

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

class CountSum {      private final Long count;      private final Integer sum;      public CountSum(Long count, Integer sum) {          this.count = count;          this.sum = sum;      }      @Override      public String toString() {          return "CountSum{" +                  "count=" + count +                  ", sum=" + sum +                  '}';      }  }

通過 Collectors.teeing 處理

CountSum countsum = Stream.of(2, 11, 1, 5, 7, 8, 12)          .collect(Collectors.teeing(                  counting(),                  summingInt(e -> e),                  CountSum::new));  System.out.println(countsum.toString());
  •  downstream1 通過 Collectors 的靜態方法 counting 進行集合計數

  •  downstream2 通過 Collectors 的靜態方法 summingInt 進行集合元素值的累加

  •  merger 通過 CountSum 構造器收集結果

運行結果:

CountSum{count=7, sum=46}

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

最大值與最小值

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

class MinMax {      private final Integer min;      private final Integer max;      public MinMax(Integer min, Integer max) {          this.min = min;          this.max = max;      }      @Override      public String toString() {          return "MinMax{" +                  "min=" + min +                  ", max=" + max +                  '}';      }  }

通過 teeing API 計算結果:

MinMax minmax = Stream.of(2, 11, 1, 5, 7, 8, 12)          .collect(Collectors.teeing(                  minBy(Comparator.naturalOrder()),                  maxBy(Comparator.naturalOrder()),                  (Optional<Integer> a, Optional<Integer> b) -> new MinMax(a.orElse(Integer.MIN_VALUE), b.orElse(Integer.MAX_VALUE))));  System.out.println(minmax.toString());
  •  downstream1 通過 Collectors 的靜態方法 minBy,通過 Comparator 比較器按照自然排序找到最小值

  •  downstream2 通過 Collectors 的靜態方法 maxBy,通過 Comparator 比較器按照自然排序找到最大值

  •  merger 通過 MinMax 構造器收集結果,只不過為了應對 NPE,將 BiFunction 的兩個入參經過 Optional 處理

運行結果: 

MinMax{min=1, max=12}

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

MinMax minmax = Stream.of(null, 2, 11, 1, 5, 7, 8, 12)                  .collect(Collectors.teeing(                          minBy(Comparator.nullsFirst(Comparator.naturalOrder())),                          maxBy(Comparator.nullsLast(Comparator.naturalOrder())),                          (Optional<Integer> a, Optional<Integer> b) -> new MinMax(a.orElse(Integer.MIN_VALUE), b.orElse(Integer.MAX_VALUE))));
  •  downstream1 處理規則是將 null 放在排序的最前面

  •  downstream2 處理規則是將 null 放在排序的最后面

  •  merger 處理時,都會執行 optional.orElse 方法,分別輸出最小值與最大值

運行結果: 

MinMax{min=-2147483648, max=2147483647}

瓜的總重和單個重量

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

// 定義瓜的類型和重量  class Melon {      private final String type;      private final int weight;      public Melon(String type, int weight) {          this.type = type;          this.weight = weight;      }      public String getType() {          return type;      }      public int getWeight() {          return weight;      }  }  // 總重和單個重量列表  class WeightsAndTotal {      private final int totalWeight;      private final List<Integer> weights;      public WeightsAndTotal(int totalWeight, List<Integer> weights) {          this.totalWeight = totalWeight;          this.weights = weights;      }      @Override      public String toString() {          return "WeightsAndTotal{" +                  "totalWeight=" + totalWeight +                  ", weights=" + weights +                  '}';      }  }

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

List<Melon> melons = Arrays.asList(new Melon("Crenshaw", 1200),      new Melon("Gac", 3000), new Melon("Hemi", 2600),      new Melon("Hemi", 1600), new Melon("Gac", 1200),      new Melon("Apollo", 2600), new Melon("Horned", 1700),      new Melon("Gac", 3000), new Melon("Hemi", 2600)  );  WeightsAndTotal weightsAndTotal = melons.stream()      .collect(Collectors.teeing(              summingInt(Melon::getWeight),              mapping(m -> m.getWeight(), toList()),              WeightsAndTotal::new));  System.out.println(weightsAndTotal.toString());
  •  downstream1 通過 Collectors 的靜態方法 summingInt 做重量累加

  •  downstream2 通過 Collectors 的靜態方法 mapping 提取出瓜的重量,并通過流的終結操作 toList() 獲取結果

  •  merger 通過 WeightsAndTotal 構造器獲取結果

運行結果: 

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

繼續一個更貼合實際的例子吧:

預約人員列表和預約人數

class Guest {      private String name;      private boolean participating;      private Integer participantsNumber;      public Guest(String name, boolean participating, Integer participantsNumber) {          this.name = name;          this.participating = participating;          this.participantsNumber = participantsNumber;      }      public boolean isParticipating() {          return participating;      }      public Integer getParticipantsNumber() {          return participantsNumber;      }      public String getName() {          return name;      }  }  class EventParticipation {      private List<String> guestNameList;      private Integer totalNumberOfParticipants;      public EventParticipation(List<String> guestNameList, Integer totalNumberOfParticipants) {          this.guestNameList = guestNameList;          this.totalNumberOfParticipants = totalNumberOfParticipants;     }      @Override      public String toString() {          return "EventParticipation { " +                  "guests = " + guestNameList +                  ", total number of participants = " + totalNumberOfParticipants +                  " }";      }  }

通過 teeing API 處理

var result = Stream.of(                  new Guest("Marco", true, 3),                  new Guest("David", false, 2),                  new Guest("Roger",true, 6))                  .collect(Collectors.teeing(                          Collectors.filtering(Guest::isParticipating, Collectors.mapping(Guest::getName, Collectors.toList())),                          Collectors.summingInt(Guest::getParticipantsNumber),                          EventParticipation::new                  ));  System.out.println(result);
  •  downstream1 通過 filtering 方法過濾出確定參加的人,并 mapping 出他們的姓名,最終放到 toList 集合中

  •  downstream2 通過 summingInt 方法計數累加

  •  merger 通過 EventParticipation 構造器收集結果

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

運行結果: 

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

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

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

凤台县| 常州市| 南靖县| 华池县| 油尖旺区| 揭阳市| 天台县| 望谟县| 新闻| 宜兴市| 油尖旺区| 奉新县| 鸡东县| 黄石市| 北海市| 徐州市| 共和县| 天峨县| 神农架林区| 香港| 淮阳县| 铜山县| 安庆市| 德令哈市| 津市市| 商都县| 林芝县| 准格尔旗| 彰化市| 苗栗市| 赤城县| 长乐市| 中超| 锦州市| 微山县| 宿松县| 德化县| 保定市| 宜丰县| 兴城市| 新竹市|