日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 8编写自定义收集器简介

發布時間:2023/12/3 java 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 8编写自定义收集器简介 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java 8引入了收集器的概念。 大多數時候,我們幾乎不使用Collectors類中的工廠方法,例如collect(toList()) , toSet()或其他更花哨的方法,例如counting()或groupingBy() 。 實際上,沒有多少人真正去研究如何定義和實現收集器。 讓我們從分析Collector<T, A, R>真正含義及其工作原理開始。

Collector<T, A, R>充當流的“接收器 ” –流將項(一個接一個)推入收集器,最后應產生一些“ 收集 ”值。 在大多數情況下,這意味著通過累積元素或將流減少到較小的對象(例如, counting()收集器僅計算元素)來構建集合(如toList() )。 每個收集器都接受類型T項,并產生類型R聚合(累積)值(例如R = List<T> )。 泛型A簡單定義了中間可變數據結構的類型,在此期間,我們將使用它來累積T型項。 類型A可以但不必與R相同-簡單來說,我們用來從輸入Stream<T>收集項目的可變數據結構可以不同于實際的輸出收集/值。 話雖如此,每個收集器都必須實現以下方法:

interface Collector<T,A,R> {Supplier<A> supplier()BiConsumer<A,T> acumulator() BinaryOperator<A> combiner() Function<A,R> finisher()Set<Characteristics> characteristics() }
  • supplier()返回一個函數,該函數創建一個累加器實例–可變數據結構,我們將使用該函數來累加類型T輸入元素。
  • accumulator()返回一個函數,該函數將累加累加器和類型T一項,即累加累加器。
  • combiner()用于將兩個累加器合并為一個。 它在并行執行收集器時使用,首先拆分輸入Stream<T>并首先獨立收集部分。
  • finisher()使用累加器A并將其轉換為類型R的結果值,例如collection。 所有這些聽起來都非常抽象,所以讓我們做一個簡單的例子。

顯然,Java 8沒有為Guava提供ImmutableSet<T>的內置收集器。 但是,創建一個非常簡單。 請記住,為了迭代地構建ImmutableSet我們使用ImmutableSet.Builder<T> –這將是我們的累加器。

import com.google.common.collect.ImmutableSet;public class ImmutableSetCollector<T> implements Collector<T, ImmutableSet.Builder<T>, ImmutableSet<T>> {@Overridepublic Supplier<ImmutableSet.Builder<T>> supplier() {return ImmutableSet::builder;}@Overridepublic BiConsumer<ImmutableSet.Builder<T>, T> accumulator() {return (builder, t) -> builder.add(t);}@Overridepublic BinaryOperator<ImmutableSet.Builder<T>> combiner() {return (left, right) -> {left.addAll(right.build());return left;};}@Overridepublic Function<ImmutableSet.Builder<T>, ImmutableSet<T>> finisher() {return ImmutableSet.Builder::build;}@Overridepublic Set<Characteristics> characteristics() {return EnumSet.of(Characteristics.UNORDERED);} }

首先,仔細研究泛型類型。 我們的ImmutableSetCollector接受類型T輸入元素,因此它適用于任何Stream<T> 。 最后,將產生預期的ImmutableSet<T> 。 ImmutableSet.Builder<T>將成為我們的中間數據結構。

  • supplier()返回創建新ImmutableSet.Builder<T>的函數。 如果您不熟悉Java 8中的lambda,則ImmutableSet::builder是() -> ImmutableSet.builder()的簡寫。
  • accumulator()返回一個函數,該函數采用builder和一個T類型的元素。 它只是將上述元素添加到構建器中。
  • combiner()返回一個函數,該函數將接受兩個生成器,并通過將一個中的所有元素添加到另一個中并返回后者來將它們變成一個。 最后finisher()返回一個函數,該函數會將ImmutableSet.Builder<T>轉換為ImmutableSet<T> 。 同樣,這是以下形式的簡寫語法: builder -> builder.build() 。
  • 最后但并非最不重要的一點是, characteristics()告知JDK我們的收集器具有什么功能。 例如,如果ImmutableSet.Builder<T>是線程安全的(不是),我們也可以說Characteristics.CONCURRENT 。

現在,我們可以使用collect()在所有地方使用自定義收集器:

final ImmutableSet<Integer> set = Arrays.asList(1, 2, 3, 4).stream().collect(new ImmutableSetCollector<>());

但是創建新實例有點冗長,因此我建議創建靜態工廠方法,類似于JDK所做的:

public class ImmutableSetCollector<T> implements Collector<T, ImmutableSet.Builder<T>, ImmutableSet<T>> {//...public static <T> Collector<T, ?, ImmutableSet<T>> toImmutableSet() {return new ImmutableSetCollector<>();} }

從現在開始,我們只需鍵入以下命令即可充分利用我們的自定義收集器: collect(toImmutableSet()) 。 在第二部分中,我們將學習如何編寫更復雜和有用的收集器。

更新資料

@akarazniewicz 指出收藏家只是折疊的冗長實現。 由于我與褶皺之間的愛與恨關系,我不得不對此發表評論。 Java 8中的收集器基本上是Scala中最復雜的折疊類型的面向對象封裝,即GenTraversableOnce.aggregate[B](z: ? B)(seqop: (B, A) ? B, combop: (B, B) ? B): B 。 aggregate()類似于fold() ,但是需要額外的combop才能將兩個B型累加器組合為一個。 將其與收集器進行比較,參數z來自seqop() supplier() , seqop()歸約運算是一個accumulator()而combop是一個combop combiner() 。 用偽代碼可以編寫:

finisher(seq.aggregate(collector.supplier())(collector.accumulator(), collector.combiner()))

GenTraversableOnce.aggregate()在可能同時減少時使用GenTraversableOnce.aggregate()就像收集器一樣)。

翻譯自: https://www.javacodegeeks.com/2014/07/introduction-to-writing-custom-collectors-in-java-8.html

總結

以上是生活随笔為你收集整理的Java 8编写自定义收集器简介的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。