java 8如何自定义收集器(collector)详解

网友投稿 383 2023-05-04


java 8如何自定义收集器(collector)详解

需求:

将 一个容器List 按照一定的字段进行分组,分组过后的值为特定的BEAN 里面的属性例如:

假定有这样一个Bean

public class SubjectOberser{

private String subjectKey;

private AbstractObserver abstractObserver;

...geter seter 方法...

}

我们需要按照 subjectKey 进行分组,分组过后的内容 应该为这样一个容器Map

map 中的key,为SubjectOberser 属性的subjectKey,值为List

实现过程

首先来看看collector 的接口定义

public interface Collector {

Supplier supplier();

BiConsumer accumulator();

Function finisher();

BinaryOperator combiner();

Set characteristics();

}

类型 T ,是在容器里面元素的类型

类型 A ,是accumulator 返回的类型,即是累加器的返回类型

类型 R ,是最终结果的类型

supplier 方法返回的结果必须为一个空的Supplier,也就是一个空的无参函数(签名就是这样的 ()->{}),在调用的时候它会创建一个空的累加器(accumulator)实例,供数据收集的时候使用,很明显如果按照我们的需求试下你自己collector 这里应该返回一个 () -> new HashMap<>() ,一个Map 来收集结果

accumulator 方法返回归约操作的函数(签名是这样的 (a,b)->void ),当遍历到流中第n个元素时,这个函数执行时会有两个参数:保存归约结果的累加器(已 收集了流中的前n-1个项目),还有第n个元素本身。签名也展示该函数是void,因为该操作是在原来的容器里面进行更新的,所以返回的是void 类型。按照需求的中的实现应该是是这样的:

public BiConsumer>, SubjectObserver> accumulator() {

http:// return (Map> acc, SubjectObserver v) -> {

if (acc.containsKey(v.getSubjectKey())){

acc.get(v.getSubjectKey()).add(v.getAbstractObserver());

}else{

List l = new ArrayList<>();

l.add(v.getAbstractObserver());

acc.put(v.getSubjectKey(),l);

}

};

}

这里的逻辑就是if else  逻辑判断就是,这个key ,在map 中是否存在,如果不存在,那么我们需要给他new一个list 的实例,不然我的的数据没有地方存储

finisher 可从名字看出方法累积过程的最后要调用的一个函数,以便将累加器对象转换为整个集合操作的最终结果。通常来说累加器的类型也是返回的结果的类型,那么就返回identity 就可以了,如果不是的话,就行自行转换了。在当前需求的情况下我们的累加器和返回结果的类型是一致的,所以这里的实现是这样的:

public Function>,

Map>> finisher(){

return Function.identity();

}

combiner 方法是将两个累加的结果进行一个合并的过程,当然这个过程并不是每一个collector 都会调用得到(后面会讲到)

按照我们的需求,只需要将两个累加器的,中间结果合并成为一个结果即可,所以是现实这样的:

public BinaryOperator>> combiner() {

return ((Map> map1,

Map> map2) -> {

map1.putAll(map2);

return map1;

});

}

characteristics 该方法返回一个 Characteristics 的集合,它有如下值可选

UNORDERED—— 归约结果不受流中项目的遍历和累积顺序的影响。

CONCURRENT—— accumulator函数可以从多个线程同时调用,且该收集器可以并行执行。如果收集器没有标为UNORDERED,那 它仅在用于用于无序数据源时才可以并行归约。

IDENTITY_ FINISH—— 这表明完成器方法返回的函数是一个不改变的函数,这种情况下,累加器对象将会直接用作合并过程 的最终结果。

public Set characteristics() {

return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));

}

最终collector 代码合在一起就是:

public class MyCollector implements Collector

Map>,

Map>> {

@Override

public Supplier>> supplier() {

return () -> new HashMap<>();

}

@Override

public BiConsumer>, SubjectObserver> accumulator() {

return (Map> acc, SubjectObserver v) -> {

if (acc.containsKey(v.getSubjectKey())) {

acc.get(v.getSubjectKey()).add(v.getAbstractObserver());

} else {

List l = new ArrayList<>();

l.add(v.getAbstractObserver());

acc.put(v.getSubjectKey(), l);

}

};

}

@Override

public BinaryOperator>> combiner() {

return ((Map> map1, Map> map2) -> {

map1.putAll(map2);

return map1;

});

}

@Override

public Function>, Map>> finisher() {

return Function.identity();

}

@Override

public Set characteristics() {

return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));

}

}

调用的过程就是:

public static Map> initObjectMap() {

ClassScaner classScaner = new ClassScaner();

Set set = classScaner.doScan("com.souche.datacenter.observer");

return set

.stream()

.filter(aClass -gtjNRJ> SubjectAnnotationResolver.getAnnotationSubjectName(aClass) != null)

.map(aClass -> {

String subjectKey = SubjectAnnotationResolver.getAnnotationSubjectName(aClass);

AbstractObserver abstractObserver = getBeanByClassName(aClass.getSimpleName());

return new SubgtjNRJjectObserver(subjectKey, abstractObserver);

}).collect(new MyCollector());

}

直接在使用的地方直接new MyCollector 就可以了

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

Map>,

Map>> {

@Override

public Supplier>> supplier() {

return () -> new HashMap<>();

}

@Override

public BiConsumer>, SubjectObserver> accumulator() {

return (Map> acc, SubjectObserver v) -> {

if (acc.containsKey(v.getSubjectKey())) {

acc.get(v.getSubjectKey()).add(v.getAbstractObserver());

} else {

List l = new ArrayList<>();

l.add(v.getAbstractObserver());

acc.put(v.getSubjectKey(), l);

}

};

}

@Override

public BinaryOperator>> combiner() {

return ((Map> map1, Map> map2) -> {

map1.putAll(map2);

return map1;

});

}

@Override

public Function>, Map>> finisher() {

return Function.identity();

}

@Override

public Set characteristics() {

return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));

}

}

调用的过程就是:

public static Map> initObjectMap() {

ClassScaner classScaner = new ClassScaner();

Set set = classScaner.doScan("com.souche.datacenter.observer");

return set

.stream()

.filter(aClass -gtjNRJ> SubjectAnnotationResolver.getAnnotationSubjectName(aClass) != null)

.map(aClass -> {

String subjectKey = SubjectAnnotationResolver.getAnnotationSubjectName(aClass);

AbstractObserver abstractObserver = getBeanByClassName(aClass.getSimpleName());

return new SubgtjNRJjectObserver(subjectKey, abstractObserver);

}).collect(new MyCollector());

}

直接在使用的地方直接new MyCollector 就可以了

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:获取实现接口的类(获取接口请求时间)
下一篇:mock测试的工具(mock test)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~