• lambda 自定义收集器


    来看一个简单的lambda表达式的两种写法

    //lambda1
    Collections.emptyList().stream().collect(Collectors.counting());
    //lambda2
    Collections.emptyList().stream().collect(HashMap::new, (map, item) -> map.put(item.getCode(), item.getValue()), HashMap::putAll);
    
    //看一下collect()方法需要传递的参数
    //lambda1参数, 
    <R, A> R collect(Collector<? super T, A, R> collector);
    
    //lambda2参数,
    <R> R collect(Supplier<R> supplier,
                  BiConsumer<R, ? super T> accumulator,
                  BiConsumer<R, R> combiner);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    可以看到, 方法的参数是Collector对象, 因此自定义收集器就是实现Collector接口, 来写自己的逻辑
    或者也可以传递三个参数supplier,accumulator,combiner也可以实现

    看一下Collector类代码 :

    
    //T : 参数类型
    //A : 容器类型
    //R : 结果类型
    public interface Collector<T, A, R> {
    
    	// supplier参数用于生成结果容器,容器类型为A
        Supplier<A> supplier();
        
    	// accumulator用于消费元素,也就是归纳元素,这里的T就是元素,它会将流中的元素一个一个与结果容器A发生操作
        BiConsumer<A, T> accumulator();
    
    	// combiner用于两个两个合并并行执行的线程的执行结果,将其合并为一个最终结果A
        BinaryOperator<A> combiner();
        
        // finisher用于将之前整合完的结果R转换成为A
        Function<A, R> finisher();
    
        // characteristics表示当前Collector的特征值,这是个不可变Set
        Set<Characteristics> characteristics();
    
    	//构造方法1, 不需要传finisher();, 容器类型和结果类型相同, 例如toList()
        public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
                                                  BiConsumer<R, T> accumulator,
                                                  BinaryOperator<R> combiner,
                                                  Characteristics... characteristics) {
            Objects.requireNonNull(supplier);
            Objects.requireNonNull(accumulator);
            Objects.requireNonNull(combiner);
            Objects.requireNonNull(characteristics);
            Set<Characteristics> cs = (characteristics.length == 0)
                                      ? Collectors.CH_ID
                                      : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
                                                                               characteristics));
            return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
        }
    
        //构造方法2, 需要传finisher();, 容器类型和结果类型不相同, 例如summingDouble()
        public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
                                                     BiConsumer<A, T> accumulator,
                                                     BinaryOperator<A> combiner,
                                                     Function<A, R> finisher,
                                                     Characteristics... characteristics) {
            Objects.requireNonNull(supplier);
            Objects.requireNonNull(accumulator);
            Objects.requireNonNull(combiner);
            Objects.requireNonNull(finisher);
            Objects.requireNonNull(characteristics);
            Set<Characteristics> cs = Collectors.CH_NOID;
            if (characteristics.length > 0) {
                cs = EnumSet.noneOf(Characteristics.class);
                Collections.addAll(cs, characteristics);
                cs = Collections.unmodifiableSet(cs);
            }
            return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
        }
    
    
        enum Characteristics {
    
            CONCURRENT,
    
            UNORDERED,
    
            IDENTITY_FINISH
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    在自定义收集器的时候, 通常用Collector.of()来构建Collector对象

    知道了自定义收集器需要的所有参数之后, 就可以尝试自己去写自己的收集器

    需求 : collectors.summingDouble()方法在求和的时候会丢失经度(里面用的是double运行), 写一个不会丢失经度的自定义收集器

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    public class TestDO implements Serializable {
    
        private String code;
    
        private Double value;
    }
    
    //初始化集合
    TestDO testDO = new TestDO("001", 75.9989);
    TestDO testDO1 = new TestDO("001", 4.7852);
    TestDO testDO3 = new TestDO("001", 19.3607);
    TestDO testDO4 = new TestDO("001", 1.3191);
    
    List<TestDO> list = Arrays.asList(testDO, testDO1, testDO3, testDO4);
    
    //MyCollectors.summingBigDecimal(TestDO::getValue)  自定义收集器
    Map<String, Double> map1 = list.stream().collect(Collectors.groupingBy(TestDO::getCode,MyCollectors.summingBigDecimal(TestDO::getValue)));
    
    
    
    public class MyCollectors {
    
        /**
         * T : 参数
         * ? : 过程中的值   就是new BigDecimal[1]
         * Double : 结果
         *
         * @return java.util.stream.Collector
         * @Description
         * @Author hc
         * @Since 2023/9/5 20:46
         * @Param mapper
         **/
        public static <T> Collector<T, ?, Double> summingBigDecimal(ToDoubleFunction<? super T> mapper) {
    
            return Collector.of(
            		//初始化容器supplier
                    () -> new BigDecimal[1],
                    //消费元素 accumulator
                    (result, item) -> {
                        if (result[0] == null) {
                            result[0] = BigDecimal.valueOf(mapper.applyAsDouble(item));
                        } else {
                            result[0] = result[0].add(BigDecimal.valueOf(mapper.applyAsDouble(item)));
                        }
                    },
                    //合并结果combiner(),parallelStream时候使用
                    (result1, result2) -> {
                        result1[0] = result1[0].add(result2[0]);
                        return result1;
                    },
                    //转换结果,finisher
                    total -> total[0].doubleValue()
            );
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    写自定义收集器只需要理解collector里面那几个参数, 就可以了

  • 相关阅读:
    嵌入式分享合集34
    1160 Forever – PAT甲级真题
    一文了解 Go 方法
    浅谈AVL树,红黑树,B树,B+树原理及应用
    外观 ( Facade ) 模式
    用 Rcpp 访问 C++ 代码
    遇到项目难点
    java项目_第163期ssm药品电子商城系统_java毕业设计
    KBQA知识图谱问答
    TeeChart Pro for .NET 2022.10.24 Crack
  • 原文地址:https://blog.csdn.net/hc1428090104/article/details/132737126