java?stream實(shí)現(xiàn)分組BigDecimal求和以及自定義分組求和
前言
隨著微服務(wù)的發(fā)展,越來越多的sql處理被放到j(luò)ava來處理,數(shù)據(jù)庫經(jīng)常會(huì)使用到對(duì)集合中的數(shù)據(jù)進(jìn)行分組求和,分組運(yùn)算等等。
那怎么樣使用java的stream優(yōu)雅的進(jìn)行分組求和或運(yùn)算呢?
一、準(zhǔn)備測(cè)試數(shù)據(jù)
這里測(cè)試數(shù)據(jù)學(xué)生,年齡類型是Integer,身高類型是BigDecimal,我們分別對(duì)身高個(gè)年齡進(jìn)行求和。
@Data @AllArgsConstructor @NoArgsConstructor public class Student { /** * 姓名 */ private String name; /** * 年齡 */ private Integer age; /** * 身高 */ private BigDecimal stature; } public class LambdaLearn { // 初始化的測(cè)試數(shù)據(jù)集合 static List<Student> list = new ArrayList<>(); static { // 初始化測(cè)試數(shù)據(jù) list.add(new Student("張三", 18, new BigDecimal("185"))); list.add(new Student("張三", 19, new BigDecimal("185"))); list.add(new Student("張三2", 20, new BigDecimal("180"))); list.add(new Student("張三3", 20, new BigDecimal("170"))); list.add(new Student("張三3", 21, new BigDecimal("172"))); } }
二、按學(xué)生姓名分組求年齡和(Integer類型的求和簡(jiǎn)單示例)
1.實(shí)現(xiàn)
// 按學(xué)生姓名分組求年齡和 public static void main(String[] args) { Map<String, Integer> ageGroup = list.stream().collect(Collectors.groupingBy(Student::getName , Collectors.summingInt(Student::getAge))); System.out.println(ageGroup); }
執(zhí)行結(jié)果:
{張三=37, 張三3=41, 張三2=20}
三、按學(xué)生姓名分組求身高和(Collectors沒有封裝對(duì)應(yīng)的API)
1.實(shí)現(xiàn)一(推薦寫法)
思路:先分組,再map轉(zhuǎn)換成身高BigDecimal,再用reduce進(jìn)行求和
public static void main(String[] args) { Map<String, BigDecimal> ageGroup = list.stream().collect(Collectors.groupingBy(Student::getName , Collectors.mapping(Student::getStature, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)))); System.out.println(ageGroup); }
執(zhí)行結(jié)果:
{張三=370, 張三3=342, 張三2=180}
2.實(shí)現(xiàn)二
思路:先分組,再收集成list,然后再map,再求和
public static void main(String[] args) { Map<String, BigDecimal> ageGroup = list.stream().collect(Collectors.groupingBy(Student::getName , Collectors.collectingAndThen(Collectors.toList() , x -> x.stream().map(Student::getStature).reduce(BigDecimal.ZERO, BigDecimal::add)))); System.out.println(ageGroup); }
執(zhí)行結(jié)果:
{張三=370, 張三3=342, 張三2=180}
3.實(shí)現(xiàn)三
思路:業(yè)務(wù)時(shí)常在分組后需要做一些判斷邏輯再進(jìn)行累加業(yè)務(wù)計(jì)算,所以自己實(shí)現(xiàn)一個(gè)收集器
1.封裝一個(gè)自定義收集器
public class MyCollector { 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(); private MyCollector() { } @SuppressWarnings("unchecked") private static <I, R> Function<I, R> castingIdentity() { return i -> (R) i; } /** * @param <T> 集合元素類型 * @param <A> 中間結(jié)果容器 * @param <R> 最終結(jié)果類型 */ 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, // 產(chǎn)生結(jié)果容器 BiConsumer<A, T> accumulator, // 累加器 BinaryOperator<A> combiner, // 將多個(gè)容器結(jié)果合并成一個(gè) Set<Characteristics> characteristics) { this(supplier, accumulator, combiner, castingIdentity(), characteristics); } @Override public BiConsumer<A, T> accumulator() { return accumulator; } @Override public Supplier<A> supplier() { return supplier; } @Override public BinaryOperator<A> combiner() { return combiner; } @Override public Function<A, R> finisher() { return finisher; } @Override public Set<Characteristics> characteristics() { return characteristics; } } public static <T> Collector<T, ?, BigDecimal> summingDecimal(ToDecimalFunction<? super T> mapper) { return new MyCollector.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); } }
2.封裝一個(gè)函數(shù)式接口
@FunctionalInterface public interface ToDecimalFunction<T> { BigDecimal applyAsDecimal(T value); }
3.使用
public static void main(String[] args) { Map<String, BigDecimal> ageGroup = list.stream().collect(Collectors.groupingBy(Student::getName , MyCollector.summingDecimal(Student::getStature))); System.out.println(ageGroup); }
總結(jié)
自定義實(shí)現(xiàn)收集器可以參考Collectors的內(nèi)部類CollectorImpl的源碼,具體解析寫到注釋中。
推薦通過模仿Collectors.summingInt()的實(shí)現(xiàn)來實(shí)現(xiàn)我們自己的收集器。
// T代表流中元素的類型,A是中間處理臨時(shí)保存類型,R代表返回結(jié)果的類型 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); } // 這里提供一個(gè)初始化的容器,用于存儲(chǔ)每次累加。即使我們求和這里也只能使用容器存儲(chǔ),否則后續(xù)計(jì)算累加結(jié)果會(huì)丟失(累加結(jié)果不是通過返回值方式修改的)。 @Override public Supplier<A> supplier() { return supplier; } // 累加計(jì)算:累加流中的每一個(gè)元素T到A容器存儲(chǔ)的結(jié)果中,這里沒有返回值,所以A必須是容器,避免數(shù)據(jù)丟失 @Override public BiConsumer<A, T> accumulator() { return accumulator; } // 這里是當(dāng)開啟parallelStream()并發(fā)處理時(shí),會(huì)得到多個(gè)結(jié)果容器A,這里對(duì)多個(gè)結(jié)果進(jìn)行合并 @Override public BinaryOperator<A> combiner() { return combiner; } // 這里是處理中間結(jié)果類型轉(zhuǎn)換成返回結(jié)果類型 @Override public Function<A, R> finisher() { return finisher; } // 這里標(biāo)記返回結(jié)果的數(shù)據(jù)類型,這里取值來自于Collector接口的內(nèi)部類Characteristics @Override public Set<Characteristics> characteristics() { return characteristics; } }
enum Characteristics { // 表示此收集器是 并發(fā)的 ,這意味著結(jié)果容器可以支持與多個(gè)線程相同的結(jié)果容器同時(shí)調(diào)用的累加器函數(shù)。 CONCURRENT, // 表示收集操作不承諾保留輸入元素的遇到順序。 UNORDERED, // 表示整理器功能是身份功能,可以被刪除。 IDENTITY_FINISH }
補(bǔ)充例子:求相同姓名的學(xué)生的年齡之和(姓名組合)
package com.TestStream; import java.util.*; import java.util.stream.Collectors; /** * @author 林高祿 * @create 2020-06-09-9:29 */ public class Demo2 { public static void main(String[] args) { List<Student> studentList = StudentUtil2.createStudentList(); // 通過姓名分組,姓名為key,相同姓名的學(xué)生為列表 Map<String, List<Student>> collect = studentList.stream().collect(Collectors.groupingBy(Student::getName, Collectors.toList())); // collect的數(shù)據(jù)為 System.out.println("collect的數(shù)據(jù)為:"); collect.forEach((key,list)-> { System.out.println("key:"+key); list.forEach(System.out::println); }); // 分組后的年齡和為 System.out.println("分組后的年齡和為:"); collect.forEach((key,list)-> System.out.println("key:"+key+",年齡和"+list.stream().mapToInt(Student::getAge).sum())); } }
運(yùn)行輸出:
collect的數(shù)據(jù)為:
key:陳文文
Student{no=1, name='陳文文', age=10, mathScore=100.0, chineseScore=90.0}
Student{no=2, name='陳文文', age=20, mathScore=90.0, chineseScore=70.0}
key:林高祿
Student{no=1, name='林高祿', age=20, mathScore=90.5, chineseScore=90.5}
Student{no=11, name='林高祿', age=20, mathScore=90.5, chineseScore=90.5}
Student{no=2, name='林高祿', age=10, mathScore=80.0, chineseScore=90.0}
Student{no=1, name='林高祿', age=30, mathScore=90.5, chineseScore=90.0}
key:1林高祿
Student{no=1, name='1林高祿', age=20, mathScore=90.5, chineseScore=90.5}
key:蔡金鑫
Student{no=1, name='蔡金鑫', age=30, mathScore=80.0, chineseScore=90.0}
分組后的年齡和為:
key:陳文文,年齡和30
key:林高祿,年齡和80
key:1林高祿,年齡和20
key:蔡金鑫,年齡和30
到此這篇關(guān)于java stream實(shí)現(xiàn)分組BigDecimal求和以及自定義分組求和的文章就介紹到這了,更多相關(guān)java stream分組BigDecimal求和內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合Redis使用@Cacheable和RedisTemplate
本文主要介紹了SpringBoot整合Redis使用@Cacheable和RedisTemplate,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07java之CSV大批量數(shù)據(jù)入庫的實(shí)現(xiàn)
本文主要介紹了java之CSV大批量數(shù)據(jù)入庫的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02Java并發(fā)編程之CountDownLatch的使用
CountDownLatch是一個(gè)倒數(shù)的同步器,常用來讓一個(gè)線程等待其他N個(gè)線程執(zhí)行完成再繼續(xù)向下執(zhí)行,本文主要介紹了CountDownLatch的具體使用方法,感興趣的可以了解一下2023-05-05Java實(shí)現(xiàn)動(dòng)態(tài)數(shù)字時(shí)鐘
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)動(dòng)態(tài)數(shù)字時(shí)鐘,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12Spring Data Jpa+SpringMVC+Jquery.pagination.js實(shí)現(xiàn)分頁示例
本文介紹了Spring Data Jpa+SpringMVC+Jquery.pagination.js實(shí)現(xiàn)分頁示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12Java異常處理運(yùn)行時(shí)異常(RuntimeException)詳解及實(shí)例
這篇文章主要介紹了 Java異常處理運(yùn)行時(shí)異常(RuntimeException)詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下http://time.qq.com/?pgv_ref=aiotime2017-05-05新建Maven工程出現(xiàn)Process?Terminated的問題解決
當(dāng)Maven出現(xiàn)"Process terminated"錯(cuò)誤時(shí),這通常是由于配置文件或路徑錯(cuò)誤導(dǎo)致的,本文主要介紹了新建Maven工程出現(xiàn)Process?Terminated的問題解決,感興趣的可以了解一下2024-04-04MyBatis如何處理MySQL字段類型date與datetime
這篇文章主要介紹了MyBatis如何處理MySQL字段類型date與datetime問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01