java 8流自定义收集器_Java 8编写自定义收集器简介
java 8流自定義收集器
Java 8引入了收集器的概念。 大多數(shù)時(shí)候,我們幾乎不使用Collectors類中的工廠方法,例如collect(toList()) , toSet()或其他更有趣的方法,例如counting()或groupingBy() 。 實(shí)際上,沒有多少人真正去研究如何定義和實(shí)現(xiàn)收集器。 讓我們從分析Collector<T, A, R>真正含義及其工作原理開始。
Collector<T, A, R>充當(dāng)流的“接收器 ” –流將項(xiàng)(一個(gè)接一個(gè))推入收集器,最后應(yīng)產(chǎn)生一些“ 收集 ”值。 在大多數(shù)情況下,這意味著通過(guò)累積元素或?qū)⒘鳒p少為更小的內(nèi)容(例如, counting()很少的元素的toList()收集器)來(lái)構(gòu)建集合(如toList() )。 每個(gè)收集器都接受類型T項(xiàng),并產(chǎn)生類型R聚合(累積)值(例如R = List<T> )。 泛型A簡(jiǎn)單定義了中間可變數(shù)據(jù)結(jié)構(gòu)的類型,在此期間,我們將使用它來(lái)累積T型項(xiàng)。 類型A可以但不必與R相同-簡(jiǎn)單來(lái)說(shuō),我們用來(lái)從輸入Stream<T>收集項(xiàng)目的可變數(shù)據(jù)結(jié)構(gòu)可以不同于實(shí)際的輸出收集/值。 話雖如此,每個(gè)收集器都必須實(shí)現(xiàn)以下方法:
interface Collector<T,A,R> {Supplier<A> supplier()BiConsumer<A,T> acumulator() BinaryOperator<A> combiner() Function<A,R> finisher()Set<Characteristics> characteristics() }- supplier()返回一個(gè)函數(shù),該函數(shù)創(chuàng)建一個(gè)累加器實(shí)例–可變數(shù)據(jù)結(jié)構(gòu),我們將使用該函數(shù)來(lái)累加類型T輸入元素。
- accumulator()返回一個(gè)函數(shù),該函數(shù)將累加累加器和類型T一項(xiàng),即累加累加器。
- combiner()用于將兩個(gè)累加器合并為一個(gè)。 它在并行執(zhí)行收集器時(shí)使用,首先拆分輸入Stream<T>并首先獨(dú)立收集部分。
- finisher()使用累加器A并將其轉(zhuǎn)換為R類型的結(jié)果值,例如collection。 所有這些聽起來(lái)都很抽象,所以讓我們做一個(gè)簡(jiǎn)單的例子。
顯然,Java 8沒有為Guava提供ImmutableSet<T>的內(nèi)置收集器。 但是,創(chuàng)建一個(gè)非常簡(jiǎn)單。 請(qǐng)記住,為了迭代地構(gòu)建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);} }首先,仔細(xì)研究泛型。 我們的ImmutableSetCollector接受類型T輸入元素,因此它適用于任何Stream<T> 。 最后,將產(chǎn)生預(yù)期的ImmutableSet<T> 。 ImmutableSet.Builder<T>將成為我們的中間數(shù)據(jù)結(jié)構(gòu)。
- supplier()返回創(chuàng)建新ImmutableSet.Builder<T>的函數(shù)。 如果您不熟悉Java 8中的lambda,則ImmutableSet::builder是() -> ImmutableSet.builder()的簡(jiǎn)寫。
- accumulator()返回一個(gè)函數(shù),該函數(shù)采用builder和一個(gè)T類型的元素。 它只是將上述元素添加到構(gòu)建器中。
- combiner()返回一個(gè)函數(shù),該函數(shù)將接受兩個(gè)生成器,并通過(guò)將一個(gè)中的所有元素添加到另一個(gè)中并返回后者來(lái)將它們變成一個(gè)。 最后finisher()返回一個(gè)函數(shù),該函數(shù)會(huì)將ImmutableSet.Builder<T>轉(zhuǎn)換為ImmutableSet<T> 。 同樣,這是以下形式的簡(jiǎn)寫語(yǔ)法: builder -> builder.build() 。
- 最后但并非最不重要的一點(diǎn)是, characteristics()告知JDK我們的收集器具有什么功能。 例如,如果ImmutableSet.Builder<T>是線程安全的(不是),我們也可以說(shuō)Characteristics.CONCURRENT 。
現(xiàn)在,我們可以使用collect()在所有地方使用自定義收集器:
final ImmutableSet<Integer> set = Arrays.asList(1, 2, 3, 4).stream().collect(new ImmutableSetCollector<>());但是創(chuàng)建新實(shí)例有點(diǎn)冗長(zhǎng),因此我建議創(chuàng)建靜態(tài)工廠方法,類似于JDK所做的:
public class ImmutableSetCollector<T> implements Collector<T, ImmutableSet.Builder<T>, ImmutableSet<T>> {//...public static <T> Collector<T, ?, ImmutableSet<T>> toImmutableSet() {return new ImmutableSetCollector<>();} }從現(xiàn)在開始,我們只需鍵入以下命令即可充分利用我們的自定義收集器: collect(toImmutableSet()) 。 在第二部分中,我們將學(xué)習(xí)如何編寫更復(fù)雜和有用的收集器。
更新資料
@akarazniewicz 指出收藏家只是折疊的冗長(zhǎng)實(shí)現(xiàn)。 由于我與褶皺之間的愛與恨關(guān)系,我不得不對(duì)此發(fā)表評(píng)論。 Java 8中的收集器基本上是Scala中最復(fù)雜的折疊類型的面向?qū)ο蠓庋b,即GenTraversableOnce.aggregate[B](z: ? B)(seqop: (B, A) ? B, combop: (B, B) ? B): B 。 aggregate()就像fold() ,但是需要額外的combop才能將兩個(gè)B型累加器組合為一個(gè)。 將其與收集器進(jìn)行比較,參數(shù)z來(lái)自seqop() supplier() , seqop()歸約運(yùn)算是一個(gè)accumulator()而combop是一個(gè)combop combiner() 。 用偽代碼可以編寫:
finisher(seq.aggregate(collector.supplier())(collector.accumulator(), collector.combiner()))GenTraversableOnce.aggregate()在可能同時(shí)進(jìn)行縮減時(shí)使用GenTraversableOnce.aggregate()就像收集器一樣)。
翻譯自: https://www.javacodegeeks.com/2014/07/introduction-to-writing-custom-collectors-in-java-8.html
java 8流自定義收集器
總結(jié)
以上是生活随笔為你收集整理的java 8流自定义收集器_Java 8编写自定义收集器简介的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 家里有八角虫怎么处理 家里有八角虫如何处
- 下一篇: Java 11新字符串方法的基准