java 8如何自定义收集器(collector)详解
需求:
将一个容器List
假定有这样一个Bean
publicclassSubjectOberser{ privateStringsubjectKey; privateAbstractObserverabstractObserver; ...geterseter方法... }
我们需要按照subjectKey进行分组,分组过后的内容应该为这样一个容器Map
map中的key,为SubjectOberser属性的subjectKey,值为List
实现过程
首先来看看collector的接口定义
publicinterfaceCollector{ Suppliersupplier(); BiConsumeraccumulator(); Functionfinisher(); BinaryOperatorcombiner(); Set characteristics(); }
类型T,是在容器里面元素的类型
类型A,是accumulator返回的类型,即是累加器的返回类型
类型R,是最终结果的类型
supplier方法返回的结果必须为一个空的Supplier,也就是一个空的无参函数(签名就是这样的()->{}),在调用的时候它会创建一个空的累加器(accumulator)实例,供数据收集的时候使用,很明显如果按照我们的需求试下你自己collector这里应该返回一个()->newHashMap<>(),一个Map来收集结果
accumulator方法返回归约操作的函数(签名是这样的(a,b)->void),当遍历到流中第n个元素时,这个函数执行时会有两个参数:保存归约结果的累加器(已收集了流中的前n-1个项目),还有第n个元素本身。签名也展示该函数是void,因为该操作是在原来的容器里面进行更新的,所以返回的是void类型。按照需求的中的实现应该是是这样的:
publicBiConsumer
这里的逻辑就是ifelse 逻辑判断就是,这个key,在map中是否存在,如果不存在,那么我们需要给他new一个list的实例,不然我的的数据没有地方存储
finisher可从名字看出方法累积过程的最后要调用的一个函数,以便将累加器对象转换为整个集合操作的最终结果。通常来说累加器的类型也是返回的结果的类型,那么就返回identity就可以了,如果不是的话,就行自行转换了。在当前需求的情况下我们的累加器和返回结果的类型是一致的,所以这里的实现是这样的:
publicFunction
combiner方法是将两个累加的结果进行一个合并的过程,当然这个过程并不是每一个collector都会调用得到(后面会讲到)
按照我们的需求,只需要将两个累加器的,中间结果合并成为一个结果即可,所以是现实这样的:
publicBinaryOperator
characteristics该方法返回一个Characteristics的集合,它有如下值可选
UNORDERED——归约结果不受流中项目的遍历和累积顺序的影响。
CONCURRENT——accumulator函数可以从多个线程同时调用,且该收集器可以并行执行。如果收集器没有标为UNORDERED,那它仅在用于用于无序数据源时才可以并行归约。
IDENTITY_FINISH——这表明完成器方法返回的函数是一个不改变的函数,这种情况下,累加器对象将会直接用作合并过程的最终结果。
publicSetcharacteristics(){ returnCollections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH)); }
最终collector代码合在一起就是:
publicclassMyCollectorimplementsCollector>, Map >>{ @Override publicSupplier
调用的过程就是:
publicstaticMap>initObjectMap(){ ClassScanerclassScaner=newClassScaner(); Set set=classScaner.doScan("com.souche.datacenter.observer"); returnset .stream() .filter(aClass->SubjectAnnotationResolver.getAnnotationSubjectName(aClass)!=null) .map(aClass->{ StringsubjectKey=SubjectAnnotationResolver.getAnnotationSubjectName(aClass); AbstractObserverabstractObserver=getBeanByClassName(aClass.getSimpleName()); returnnewSubjectObserver(subjectKey,abstractObserver); }).collect(newMyCollector()); }
直接在使用的地方直接newMyCollector就可以了
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。