java Collectors 分组求和

java Collectors 分组求和

1. 分组 groupingBy、groupingByConcurrent

// 线程安全分组
ConcurrentMap<Integer, List<Student>> concurrentMap = list.stream().collect(Collectors.groupingByConcurrent(Student::getId));
// 不安全分组
ConcurrentMap<Integer, List<Student>> concurrentMap = list.stream().collect(Collectors.groupingBy(Student::getId));

2. 求和 Collectors.summingXXX()

2.1第一种 Collectors.summingXXX()封装求和

使用Collectors里封装的方法 进行分组求和

求和方法(除外 Bigdemcail)

summingInt();
summingLong();
summingDouble();
sumWithCompensation();
computeFinalSum();
......
        Map<String, Integer> ageGroup = list.stream().collect(Collectors.groupingBy(Student::getName, Collectors.summingInt(Student::getAge)));

2.2第二种 自定义一个SumDecimalFunction 求和 补全
package CollectorsTest;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collector;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

/**
 * @author : DJ032915
 * @description :
 * @program :
 * @date : 2023-04-19
 */

public class SumDecimalFunction {
        static final Set<Collector.Characteristics> CH_CONCURRENT_ID
            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
            Collector.Characteristics.UNORDERED,
            Collector.Characteristics.IDENTITY_FINISH));
    static final Set<Collector.Characteristics> CH_CONCURRENT_NOID
            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
            Collector.Characteristics.UNORDERED));
    static final Set<Collector.Characteristics> CH_ID
            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
    static final Set<Collector.Characteristics> CH_UNORDERED_ID
            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
            Collector.Characteristics.IDENTITY_FINISH));
    static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();

   

    @SuppressWarnings("unchecked")
    private static <I, R> Function<I, R> castingIdentity() {
        return i -> (R) i;
    }

    /**
     * @param <T> 集合元素类型
     * @param <A> 中间结果容器
     * @param <R> 最终结果类型
     */
    // T代表流中元素的类型,A是中间处理临时保存类型,R代表返回结果的类型
    static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
        private final Supplier<A> supplier;
        private final BiConsumer<A, T> accumulator;
        private final BinaryOperator<A> combiner;
        private final Function<A, R> finisher;
        private final Set<Characteristics> characteristics;

        CollectorImpl(Supplier<A> supplier,
                      BiConsumer<A, T> accumulator,
                      BinaryOperator<A> combiner,
                      Function<A, R> finisher,
                      Set<Characteristics> characteristics) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.combiner = combiner;
            this.finisher = finisher;
            this.characteristics = characteristics;
        }

        CollectorImpl(Supplier<A> supplier,  // 产生结果容器
                      BiConsumer<A, T> accumulator,  // 累加器
                      BinaryOperator<A> combiner, // 将多个容器结果合并成一个
                      Set<Characteristics> characteristics) {
            this(supplier, accumulator, combiner, castingIdentity(), characteristics);
        }
        // 这里提供一个初始化的容器,用于存储每次累加。即使我们求和这里也只能使用容器存储,否则后续计算累加结果会丢失(累加结果不是通过返回值方式修改的)。
        @Override
        public BiConsumer<A, T> accumulator() {
            return accumulator;
        }
        // 累加计算:累加流中的每一个元素T到A容器存储的结果中,这里没有返回值,所以A必须是容器,避免数据丢失
        @Override
        public Supplier<A> supplier() {
            return supplier;
        }
        // 这里是当开启parallelStream()并发处理时,会得到多个结果容器A,这里对多个结果进行合并
        @Override
        public BinaryOperator<A> combiner() {
            return combiner;
        }
        // 这里是处理中间结果类型转换成返回结果类型
        @Override
        public Function<A, R> finisher() {
            return finisher;
        }
        // 这里标记返回结果的数据类型,这里取值来自于Collector接口的内部类Characteristics
        @Override
        public Set<Characteristics> characteristics() {
            return characteristics;
        }
    }

    public static <T> Collector<T, ?, BigDecimal> summingDecimal(ToDecimalFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new BigDecimal[1],
                (a, t) -> {
                    if (a[0] == null) {
                        a[0] = BigDecimal.ZERO;
                    }
                    a[0] = a[0].add(Optional.ofNullable(mapper.applyAsDecimal(t)).orElse(BigDecimal.ZERO));
                },
                (a, b) -> {
                    a[0] = a[0].add(Optional.ofNullable(b[0]).orElse(BigDecimal.ZERO));
                    return a;
                },
                a -> a[0], CH_NOID);
    }

    /**
     * 函数式接口首先必须是一个接口,接口里面只能有一个抽象方法(允许有默认方法、静态方法等);这种类型的接口也称为SAM接口,即Single Abstract Method Interface。
     * @param <T>
     * TIPS:加不加@FunctionalInterface注解对于接口是不是函数式接口没有影响,该注解只是提示编译器去检查接口是否仅包含一个抽象方法,即,是否符合函数式编程的定义。
     */
    @FunctionalInterface
    public interface ToDecimalFunction<T> {

        BigDecimal applyAsDecimal(T value);
    }
    enum Characteristics {
        // 表示此收集器是 并发的 ,这意味着结果容器可以支持与多个线程相同的结果容器同时调用的累加器函数。
        CONCURRENT,

        // 表示收集操作不承诺保留输入元素的遇到顺序。
        UNORDERED,

        // 表示整理器功能是身份功能,可以被删除。
        IDENTITY_FINISH
    }

}

2.3. 复杂方式分组求和

Collectors.groupingBy() 分组、求和、统计、平均、最大(小)值

本文链接:https://blog.csdn.net/echoJP_/article/details/108160728

3. 测试

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private int age;
    /**
     * 身高
     */
    private BigDecimal stature;
    /**
     * 学费
     */
    private Double money;

}
public static void main(String[] args) {
         List<Student> list = new ArrayList<>();

         {
            // 初始化测试数据
            list.add(new Student("张三", 18, new BigDecimal("185"),35.56));
            list.add(new Student("张三", 19, new BigDecimal("185"),98.23));
            list.add(new Student("张三2", 20, new BigDecimal("180"),234.21));
            list.add(new Student("张三3", 20, new BigDecimal("170"),12345.1));
            list.add(new Student("张三3", 21, new BigDecimal("172"),876.23));
        }
        Map<String, BigDecimal> statureGroup = list.stream().collect(Collectors.groupingBy(Student::getName
                , SumDecimalFunction.summingDecimal(Student::getStature)));
        System.out.println(statureGroup);

        Map<String, Integer> ageGroup = list.stream().collect(Collectors.groupingBy(Student::getName, Collectors.summingInt(Student::getAge)));
        /**
         * JDK 8中引入的三个新类是java.util包的DoubleSummaryStatistics , IntSummaryStatistics和LongSummaryStatistics 。
         * 这些类使计算元素总数,元素最小值,元素最大值,元素平均值以及双精度,整数或long的集合中的元素总和变得轻松快捷。
         * 每个类的类级别Javadoc文档都以相同的单句开头,
         * 简洁地表达了这一点,并将每个句子描述为“用于收集统计信息(例如,计数,最小值,最大值,总和和平均值)的状态对象”。
         */
        Map<String, DoubleSummaryStatistics> moneyGroup = list.stream().collect(Collectors.groupingBy(Student::getName, Collectors.summarizingDouble(Student::getMoney)));

        System.out.println("stature: "+statureGroup);
        System.out.println("age"+ageGroup);
        System.out.println("money"+moneyGroup);
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,可以使用Stream的groupingBy和summingLong方法来实现List的分组求和。首先,使用groupingBy方法按照指定的属性进行分组,然后使用summingLong方法对每个分组的元素进行求和。最后,可以通过entrySet方法将结果取出并保存到对应的列表中。 示例代码如下: 1. 首先,创建一个Map对象,用于存储分组求和的结果: Map<String, Long> map = list.stream() .collect(Collectors.groupingBy(TbSteelSemiProduct::getQlName, Collectors.summingLong(TbSteelSemiProduct::getGjjgSjsl))); 2. 然后,使用entrySet方法将map集合中的映射关系取出,并将结果保存到对应的列表中: Set<Entry<String, Long>> entrySet = map.entrySet(); for (Entry<String, Long> entry : entrySet) { xList.add(entry.getKey()); yList.add(entry.getValue().toString()); } 另外,如果需要对List中的其他类型进行求和,可以使用summingInt或mapToInt方法。summingInt方法对整型属性进行求和,而mapToInt方法将对象转换为整型后进行求和。 示例代码如下: 1. 使用summingInt方法对User对象的年龄属性进行求和: int ageSum = userList.stream() .collect(Collectors.summingInt(User::getAge)); 2. 使用mapToInt方法将User对象的年龄属性转换为整型后进行求和: int ageSumTwo = userList.stream() .mapToInt(User::getAge) .sum(); 这样就可以实现对Java List的分组求和操作了。引用提供了基于Stream的groupingBy和summingLong方法的示例代码,而引用提供了关于Java 8 Stream自定义分组求和并排序的实现的详细介绍。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Java 8中 直接通过List进行分组求和](https://blog.csdn.net/qq_16165363/article/details/117704861)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [java8 stream自定义分组求和并排序的实现](https://download.csdn.net/download/weixin_38613330/12743652)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值