java 8如何自定義收集器(collector)詳解
需求:
將 一個(gè)容器List<Bean> 按照一定的字段進(jìn)行分組,分組過(guò)后的值為特定的BEAN 里面的屬性例如:
假定有這樣一個(gè)Bean
public class SubjectOberser{ private String subjectKey; private AbstractObserver abstractObserver; ...geter seter 方法... }
我們需要按照 subjectKey 進(jìn)行分組,分組過(guò)后的內(nèi)容 應(yīng)該為這樣一個(gè)容器Map<String,List<AbstractObserver>>
map 中的key,為SubjectOberser 屬性的subjectKey,值為List<AbstractObserver>
實(shí)現(xiàn)過(guò)程
首先來(lái)看看collector 的接口定義
public interface Collector<T, A, R> { Supplier<A> supplier(); BiConsumer<A, T> accumulator(); Function<A, R> finisher(); BinaryOperator<A> combiner(); Set<Characteristics> characteristics(); }
類(lèi)型 T ,是在容器里面元素的類(lèi)型
類(lèi)型 A ,是accumulator 返回的類(lèi)型,即是累加器的返回類(lèi)型
類(lèi)型 R ,是最終結(jié)果的類(lèi)型
supplier 方法返回的結(jié)果必須為一個(gè)空的Supplier,也就是一個(gè)空的無(wú)參函數(shù)(簽名就是這樣的 ()->{}),在調(diào)用的時(shí)候它會(huì)創(chuàng)建一個(gè)空的累加器(accumulator)實(shí)例,供數(shù)據(jù)收集的時(shí)候使用,很明顯如果按照我們的需求試下你自己collector 這里應(yīng)該返回一個(gè) () -> new HashMap<>()
,一個(gè)Map 來(lái)收集結(jié)果
accumulator 方法返回歸約操作的函數(shù)(簽名是這樣的 (a,b)->void ),當(dāng)遍歷到流中第n個(gè)元素時(shí),這個(gè)函數(shù)執(zhí)行時(shí)會(huì)有兩個(gè)參數(shù):保存歸約結(jié)果的累加器(已 收集了流中的前n-1個(gè)項(xiàng)目),還有第n個(gè)元素本身。簽名也展示該函數(shù)是void,因?yàn)樵摬僮魇窃谠瓉?lái)的容器里面進(jìn)行更新的,所以返回的是void 類(lèi)型。按照需求的中的實(shí)現(xiàn)應(yīng)該是是這樣的:
public BiConsumer<Map<String, List<AbstractObserver>>, SubjectObserver> accumulator() { return (Map<String, List<AbstractObserver>> acc, SubjectObserver v) -> { if (acc.containsKey(v.getSubjectKey())){ acc.get(v.getSubjectKey()).add(v.getAbstractObserver()); }else{ List<AbstractObserver> l = new ArrayList<>(); l.add(v.getAbstractObserver()); acc.put(v.getSubjectKey(),l); } }; }
這里的邏輯就是if else 邏輯判斷就是,這個(gè)key ,在map 中是否存在,如果不存在,那么我們需要給他new一個(gè)list 的實(shí)例,不然我的的數(shù)據(jù)沒(méi)有地方存儲(chǔ)
finisher 可從名字看出方法累積過(guò)程的最后要調(diào)用的一個(gè)函數(shù),以便將累加器對(duì)象轉(zhuǎn)換為整個(gè)集合操作的最終結(jié)果。通常來(lái)說(shuō)累加器的類(lèi)型也是返回的結(jié)果的類(lèi)型,那么就返回identity 就可以了,如果不是的話(huà),就行自行轉(zhuǎn)換了。在當(dāng)前需求的情況下我們的累加器和返回結(jié)果的類(lèi)型是一致的,所以這里的實(shí)現(xiàn)是這樣的:
public Function<Map<String, List<AbstractObserver>>, Map<String, List<AbstractObserver>>> finisher(){ return Function.identity(); }
combiner 方法是將兩個(gè)累加的結(jié)果進(jìn)行一個(gè)合并的過(guò)程,當(dāng)然這個(gè)過(guò)程并不是每一個(gè)collector 都會(huì)調(diào)用得到(后面會(huì)講到)
按照我們的需求,只需要將兩個(gè)累加器的,中間結(jié)果合并成為一個(gè)結(jié)果即可,所以是現(xiàn)實(shí)這樣的:
public BinaryOperator<Map<String, List<AbstractObserver>>> combiner() { return ((Map<String, List<AbstractObserver>> map1, Map<String, List<AbstractObserver>> map2) -> { map1.putAll(map2); return map1; }); }
characteristics 該方法返回一個(gè) Characteristics 的集合,它有如下值可選
UNORDERED—— 歸約結(jié)果不受流中項(xiàng)目的遍歷和累積順序的影響。
CONCURRENT—— accumulator函數(shù)可以從多個(gè)線(xiàn)程同時(shí)調(diào)用,且該收集器可以并行執(zhí)行。如果收集器沒(méi)有標(biāo)為UNORDERED,那 它僅在用于用于無(wú)序數(shù)據(jù)源時(shí)才可以并行歸約。
IDENTITY_ FINISH—— 這表明完成器方法返回的函數(shù)是一個(gè)不改變的函數(shù),這種情況下,累加器對(duì)象將會(huì)直接用作合并過(guò)程 的最終結(jié)果。
public Set<Characteristics> characteristics() { return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH)); }
最終collector 代碼合在一起就是:
public class MyCollector implements Collector<SubjectObserver, Map<String, List<AbstractObserver>>, Map<String, List<AbstractObserver>>> { @Override public Supplier<Map<String, List<AbstractObserver>>> supplier() { return () -> new HashMap<>(); } @Override public BiConsumer<Map<String, List<AbstractObserver>>, SubjectObserver> accumulator() { return (Map<String, List<AbstractObserver>> acc, SubjectObserver v) -> { if (acc.containsKey(v.getSubjectKey())) { acc.get(v.getSubjectKey()).add(v.getAbstractObserver()); } else { List<AbstractObserver> l = new ArrayList<>(); l.add(v.getAbstractObserver()); acc.put(v.getSubjectKey(), l); } }; } @Override public BinaryOperator<Map<String, List<AbstractObserver>>> combiner() { return ((Map<String, List<AbstractObserver>> map1, Map<String, List<AbstractObserver>> map2) -> { map1.putAll(map2); return map1; }); } @Override public Function<Map<String, List<AbstractObserver>>, Map<String, List<AbstractObserver>>> finisher() { return Function.identity(); } @Override public Set<Characteristics> characteristics() { return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH)); } }
調(diào)用的過(guò)程就是:
public static Map<String, List<AbstractObserver>> initObjectMap() { ClassScaner classScaner = new ClassScaner(); Set<Class> set = classScaner.doScan("com.souche.datacenter.observer"); return set .stream() .filter(aClass -> SubjectAnnotationResolver.getAnnotationSubjectName(aClass) != null) .map(aClass -> { String subjectKey = SubjectAnnotationResolver.getAnnotationSubjectName(aClass); AbstractObserver abstractObserver = getBeanByClassName(aClass.getSimpleName()); return new SubjectObserver(subjectKey, abstractObserver); }).collect(new MyCollector()); }
直接在使用的地方直接new MyCollector
就可以了
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
三道java新手入門(mén)面試題,通往自由的道路--鎖+Volatile
這篇文章主要為大家分享了最有價(jià)值的3道多線(xiàn)程面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,對(duì)hashCode方法的設(shè)計(jì)、垃圾收集的堆和代進(jìn)行剖析,感興趣的小伙伴們可以參考一下2021-07-07springboot如何使用AOP做訪(fǎng)問(wèn)請(qǐng)求日志
這篇文章主要介紹了springboot如何使用AOP做訪(fǎng)問(wèn)請(qǐng)求日志,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01@Valid注解的作用及@Valid注解與@Validated的區(qū)別
這篇文章主要介紹了@Valid注解的作用及@Valid注解與@Validated的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08MyBatis-Plus通過(guò)插件將數(shù)據(jù)庫(kù)表生成Entiry,Mapper.xml,Mapper.class的方式
今天小編就為大家分享一篇關(guān)于MyBatis-Plus通過(guò)插件將數(shù)據(jù)庫(kù)表生成Entiry,Mapper.xml,Mapper.class的方式,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02如何查找YUM安裝的JAVA_HOME環(huán)境變量詳解
這篇文章主要給大家介紹了關(guān)于如何查找YUM安裝的JAVA_HOME環(huán)境變量的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10Java?I/O?(Input/Output)文件字節(jié)流舉例詳解
Java的輸入輸出流(IO)是用于與外部設(shè)備(如文件、網(wǎng)絡(luò)連接等)進(jìn)行數(shù)據(jù)交互的機(jī)制,下面這篇文章主要給大家介紹了關(guān)于Java?I/O?(Input/Output)文件字節(jié)流的相關(guān)資料,需要的朋友可以參考下2024-08-08