全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

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

需求:

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

假定有这样一个Bean

 public class SubjectOberser{
  private String subjectKey;
  private AbstractObserver abstractObserver;
  ...geter seter 方法...
 } 

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

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

实现过程

首先来看看collector 的接口定义

 public interface Collector<T, A, R> { 
   Supplier<A> supplier();
   BiConsumer<A, T> accumulator();
   Function<A, R> finisher();
   BinaryOperator<A> combiner();
   Set<Characteristics> characteristics();
 }

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

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

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

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

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

 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  逻辑判断就是,这个key ,在map 中是否存在,如果不存在,那么我们需要给他new一个list 的实例,不然我的的数据没有地方存储

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

 public Function<Map<String, List<AbstractObserver>>,
     Map<String, List<AbstractObserver>>> finisher(){
   return Function.identity();
 }

combiner 方法是将两个累加的结果进行一个合并的过程,当然这个过程并不是每一个collector 都会调用得到(后面会讲到)
按照我们的需求,只需要将两个累加器的,中间结果合并成为一个结果即可,所以是现实这样的:

  public BinaryOperator<Map<String, List<AbstractObserver>>> combiner() {
  return ((Map<String, List<AbstractObserver>> map1, 
    Map<String, List<AbstractObserver>> map2) -> {
     map1.putAll(map2);
     return map1;
   });
 }

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

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

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

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

   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));
  }
 }

调用的过程就是:

 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 就可以了

总结

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


# java8  # collector  # java  # 垃圾收集器  # Java9中新增的Collector收集器  # Java8 Stream Collectors收集器使用方法解析  # java收集器Collector案例汇总  # 累加器  # 是这样  # 是一个  # 是在  # 遍历  # 这样一个  # 值为  # 就可以  # 的是  # 情况下  # 收集器  # 也就  # 多个  # 将会  # 给他  # 只需  # 你自己  # 就行  # 不受  # 不存在 


相关文章: 建站主机数据库如何配置才能提升网站性能?  建站之星如何配置系统实现高效建站?  较简单的网站制作软件有哪些,手机版网页制作用什么软件?  c# 在高并发下使用反射发射(Reflection.Emit)的性能  如何通过宝塔面板实现本地网站访问?  如何在云主机快速搭建网站站点?  如何在腾讯云服务器上快速搭建个人网站?  如何快速登录WAP自助建站平台?  武清网站制作公司,天津武清个人营业执照注销查询系统网站?  IOS倒计时设置UIButton标题title的抖动问题  Bpmn 2.0的XML文件怎么画流程图  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  C++ static_cast和dynamic_cast区别_C++静态转换与动态类型安全转换  网站海报制作教学视频教程,有什么免费的高清可商用图片网站,用于海报设计?  建站之星后台密码遗忘?如何快速找回?  建站之星与建站宝盒如何选择最佳方案?  如何构建满足综合性能需求的优质建站方案?  官网网站制作腾讯审核要多久,联想路由器newifi官网  如何在云主机上快速搭建网站?  正规网站制作公司有哪些,目前国内哪家网页网站制作设计公司比较专业靠谱?口碑好?  韩国服务器如何优化跨境访问实现高效连接?  家庭服务器如何搭建个人网站?  如何快速生成高效建站系统源代码?  建站之星安装步骤有哪些常见问题?  如何快速搭建安全的FTP站点?  电商网站制作公司有哪些,1688网是什么意思?  教程网站设计制作软件,怎么创建自己的一个网站?  北京网页设计制作网站有哪些,继续教育自动播放怎么设置?  子杰智能建站系统|零代码开发与AI生成SEO优化指南  C++中的Pimpl idiom是什么,有什么好处?(隐藏实现)  一键网站制作软件,义乌购一件代发流程?  高防服务器租用首荐平台,企业级优惠套餐快速部署  想学网站制作怎么学,建立一个网站要花费多少?  建站之星后台搭建步骤解析:模板选择与产品管理实操指南  建站之星IIS配置教程:代码生成技巧与站点搭建指南  网站制作与设计教程,如何制作一个企业网站,建设网站的基本步骤有哪些?  利用JavaScript实现拖拽改变元素大小  ppt制作免费网站有哪些,ppt模板免费下载网站?  网站制作专业公司有哪些,如何制作一个企业网站,建设网站的基本步骤有哪些?  北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  大同网页,大同瑞慈医院官网?  北京专业网站制作设计师招聘,北京白云观官方网站?  简单实现Android文件上传  如何通过虚拟主机快速完成网站搭建?  5种Android数据存储方式汇总  seo网站制作优化,网站SEO优化步骤有哪些?  企业微网站怎么做,公司网站和公众号有什么区别?  义乌企业网站制作公司,请问义乌比较好的批发小商品的网站是什么?  网站制作大概要多少钱一个,做一个平台网站大概多少钱?  桂林网站制作公司有哪些,桂林马拉松怎么报名? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。