Java8 新特性 Colletor 收集器自定义

最近工作中需要用到在一个乘机人列表中先按照乘机人类型分类,在对分组后的元素属性进行聚合,以达到一个 K -> V => ADT -> 张三;李四;王五,这样的Map结构,(其实就是不想用filter过滤在join),但是普通常用的流收集器是达不到这样的效果的,最后经过研究Collector并且参考资料后总结自定义一个收集器来操作运转,话不多说了,贴代码

先贴一份demo demo代码

// Bean对象,模拟
@Data
@Accessors(chain = true)
class TestBean {
    public String name;
    public Integer age;
    public String passengerType;
    public LocalDate localDate;
    public LocalDateTime localDateTime;
    public LocalTime localTime;
}
	@Test
    public void test() {
        /**
         * Collector有五个函数式接口
         * 1、Supplier<A> supplier();
         * 这个是一个初始化函数,用来定义一个中间操作收集器,比如 ArrayList
         *
         * 2、BiConsumer<A, T> accumulator();
         * 这个就是收集器操作了
         *
         * 3、BinaryOperator<A> combiner();
         * 这个是多线程情况下合并收集器的操作,比如 ArrayList.addAll,将输入元素合并到结果容器中
         *
         * 4、Function<A, R> finisher();
         * 这个是一个结束操作,也就是下流收集器,合并两个结果容器(并行流使用,将多个线程产生的结果容器合并)
         *
         * 5、Set<Characteristics> characteristics();
         */
        Collector<TestBean, long[], Long> collector = new Collector<>() {
            @Override
            public Supplier<List<String>> supplier() {
                System.out.println("supplier invoked");
                return new Supplier<List<String>>() {
                    @Override
                    public List<String> get() {
                    	// 定义一个收集器,用来保存所有的姓名
                    	// 这里使用匿名内部类是为了在学习阶段更好的理解
                    	// 不然一开始就用lambda的话我保证你的头会炸裂,后面会有lambda简化的代码
                        return new ArrayList<>();
                    }
                };
            }

            @Override
            public BiConsumer<List<String>, TestBean> accumulator() {
                System.out.println("accumulator invoked");
                return new BiConsumer<List<String>, TestBean>() {
                    @Override
                    public void accept(List<String> strings, TestBean testBean) {
                    	// 中间收集时的添加操作
                        strings.add(testBean.getName());
                    }
                };
            }

            @Override
            public BinaryOperator<List<String>> combiner() {
                System.out.println("combiner invoked");
                // 这里时并行的合并,用lambda可以表达为 (l1, l2) -> l1.addAll(l2) 再把l1 return出去
                // 但是我这里没有用并行,就没操作了
                return null;
            }

            @Override
            public Function<List<String>, String> finisher() {
                System.out.println("finisher invoked");
                return new Function<List<String>, String>() {
                    @Override
                    public String apply(List<String> strings) {
                    	// 结尾的收集操作,这里就把list给合并了,用的hutool工具类
                        return StrUtil.join(",", strings);
                    }
                };
            }

            @Override
            public Set<Characteristics> characteristics() {
                System.out.println("characteristics invoked");

//                return Collections.unmodifiableSet(EnumSet
//                        .of(Collector.Characteristics.IDENTITY_FINISH));
                return Collections.emptySet();
            }
        };
        System.err.println(sl.toString());
    }

看一看lambda版本

    @Test
    public void test4() {
        List<TestBean> testBeanList = new ArrayList<>();
        testBeanList.add(new TestBean().setName("name1").setPassengerType("ADT").setAge(1));
        testBeanList.add(new TestBean().setName("name2").setPassengerType("ADT").setAge(1));
        testBeanList.add(new TestBean().setName("name3").setPassengerType("INF").setAge(2));
        testBeanList.add(new TestBean().setName("name4").setPassengerType("INF").setAge(1));
        testBeanList.add(new TestBean().setName("name5").setPassengerType("CLD").setAge(2));
        testBeanList.add(new TestBean().setName("name6").setPassengerType("CLD").setAge(3));
        testBeanList.add(new TestBean().setName("name7").setPassengerType("ADT").setAge(3));
        Collector<TestBean, List<String>, String> collector = new Collector<TestBean, List<String>, String>() {
            @Override
            public Supplier<List<String>> supplier() {
                return ArrayList::new;
            }

            @Override
            public BiConsumer<List<String>, TestBean> accumulator() {
                return (list1, bean) -> list1.add(bean.getName());
            }

            @Override
            public BinaryOperator<List<String>> combiner() {
                return (list1, list2) -> {
                    list1.addAll(list2);
                    return list1;
                };
            }

            @Override
            public Function<List<String>, String> finisher() {
                return (list) -> StrUtil.join(";", list);
            }

            @Override
            public Set<Characteristics> characteristics() {
                return Collections.EMPTY_SET;
            }
        };
        Map<String, String> collect = testBeanList.stream().collect(Collectors.groupingBy(TestBean::getPassengerType, collector));
        System.out.println(collect);
        // 结果:{INF=name3;name4, ADT=name1;name2;name7, CLD=name5;name6}
    }

因为平时工作经常用到
Map<Integer, Long> collect = testBeanList.stream().collect(Collectors.groupingBy(TestBean::getAge, Collectors.counting()));
这个分组统计数量,索性也就自己手写了一份简单版的统计

    @Test
    public void test3() {
        List<TestBean> testBeanList = new ArrayList<>();
        testBeanList.add(new TestBean().setName("name1").setPassengerType("ADT").setAge(1));
        testBeanList.add(new TestBean().setName("name2").setPassengerType("ADT").setAge(1));
        testBeanList.add(new TestBean().setName("name3").setPassengerType("INF").setAge(2));
        testBeanList.add(new TestBean().setName("name4").setPassengerType("INF").setAge(1));
        testBeanList.add(new TestBean().setName("name5").setPassengerType("CLD").setAge(2));
        testBeanList.add(new TestBean().setName("name6").setPassengerType("CLD").setAge(3));
        testBeanList.add(new TestBean().setName("name7").setPassengerType("ADT").setAge(3));
        Collector<TestBean, long[], Long> collector = new Collector<>() {
            @Override
            public Supplier<long[]> supplier() {
                return () -> new long[1];
            }

            @Override
            public BiConsumer<long[], TestBean> accumulator() {
                return (res, bean) -> res[0] += 1;
            }

            @Override
            public BinaryOperator<long[]> combiner() {
                return (longs1, longs2) -> new long[]{(longs1[0] + longs2[0])};
            }

            @Override
            public Function<long[], Long> finisher() {
                return longs -> longs[0];
            }

            @Override
            public Set<Characteristics> characteristics() {
                return Collections.emptySet();
            }
        };
        Map<String, Long> collect = testBeanList.stream().collect(Collectors.groupingBy(TestBean::getPassengerType, collector));
        System.out.println(collect);
    }

再贴一下简化版:

    @Test
    public void test5() {
        List<TestBean> testBeanList = new ArrayList<>();
        testBeanList.add(new TestBean().setName("刘一").setPassengerType("ADT").setAge(1));
        testBeanList.add(new TestBean().setName("周二").setPassengerType("ADT").setAge(1));
        testBeanList.add(new TestBean().setName("林三").setPassengerType("INF").setAge(2));
        testBeanList.add(new TestBean().setName("李四").setPassengerType("INF").setAge(1));
        testBeanList.add(new TestBean().setName("王五").setPassengerType("CLD").setAge(2));
        testBeanList.add(new TestBean().setName("赵六").setPassengerType("CLD").setAge(3));
        testBeanList.add(new TestBean().setName("张七").setPassengerType("ADT").setAge(3));

        Map<String, String> collect = testBeanList.stream().collect(Collectors.groupingBy(TestBean::getPassengerType, Collector.of(
                (Supplier<ArrayList<String>>) ArrayList::new,
                (ls, dto) -> ls.add(dto.getName()),
                (ls1, ls2) -> { ls1.addAll(ls2); return ls1; },
                ls -> StrUtil.join(";", ls))));
        System.out.println(collect);
        // {INF=林三;李四, ADT=刘一;周二;张七, CLD=王五;赵六}
    }

折腾了大半天,最后贴一下资料参考大佬的博客地址https://blog.csdn.net/xiliunian/article/details/88773718

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值