springboot升级到jdk21最新教程(2023年)

 更新时间:2023年10月27日 09:06:11   作者:JavaGPT  
你还在使用jdk8?快来看看最新出炉的SpringBoot+jdk21如何使用,下面这篇文章主要给大家介绍了关于springboot升级到jdk21的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

随着微服务的发展,越来越多的sql处理被放到java来处理,数据库经常会使用到对集合中的数据进行分组求和,分组运算等等。

那怎么样使用java的stream优雅的进行分组求和或运算呢?

一、准备测试数据

这里测试数据学生,年龄类型是Integer,身高类型是BigDecimal,我们分别对身高个年龄进行求和。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 身高
     */
    private BigDecimal stature;
}

public class LambdaLearn {
	// 初始化的测试数据集合
    static List<Student> list = new ArrayList<>();

    static {
    // 初始化测试数据
        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")));
    }
}

二、按学生姓名分组求年龄和(Integer类型的求和简单示例)

1.实现

// 按学生姓名分组求年龄和
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);
}

执行结果:
{张三=37, 张三3=41, 张三2=20}

三、按学生姓名分组求身高和(Collectors没有封装对应的API)

1.实现一(推荐写法)

思路:先分组,再map转换成身高BigDecimal,再用reduce进行求和

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

执行结果:
{张三=370, 张三3=342, 张三2=180}

2.实现二

思路:先分组,再收集成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);
}

执行结果:
{张三=370, 张三3=342, 张三2=180}

3.实现三

思路:业务时常在分组后需要做一些判断逻辑再进行累加业务计算,所以自己实现一个收集器

1.封装一个自定义收集器

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> 中间结果容器
     * @param <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;
        }
        @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.封装一个函数式接口

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

总结

自定义实现收集器可以参考Collectors的内部类CollectorImpl的源码,具体解析写到注释中。

推荐通过模仿Collectors.summingInt()的实现来实现我们自己的收集器。

// 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 Supplier<A> supplier() {
            return supplier;
        }
        
        // 累加计算:累加流中的每一个元素T到A容器存储的结果中,这里没有返回值,所以A必须是容器,避免数据丢失
        @Override
        public BiConsumer<A, T> accumulator() {
            return accumulator;
        }
        
        // 这里是当开启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;
        }
    }
enum Characteristics {
// 表示此收集器是 并发的 ,这意味着结果容器可以支持与多个线程相同的结果容器同时调用的累加器函数。 
    CONCURRENT,

// 表示收集操作不承诺保留输入元素的遇到顺序。
    UNORDERED,
    
// 表示整理器功能是身份功能,可以被删除。 
    IDENTITY_FINISH
}

到此这篇关于springboot升级到jdk21的文章就介绍到这了,更多相关springboot升级到jdk21内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springboot集成SpringState状态机的实现

    Springboot集成SpringState状态机的实现

    本文主要介绍了Springboot集成SpringState状态机的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-06-06
  • mybatis使用xml进行增删改查代码解析

    mybatis使用xml进行增删改查代码解析

    这篇文章主要介绍了mybatis使用xml进行增删改查代码解析,分享了相关配置和代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-02-02
  • 解析springBoot-actuator项目构造中health端点工作原理

    解析springBoot-actuator项目构造中health端点工作原理

    这篇文章主要介绍了springBoot-actuator中health端点工作原理,对spring-boot-actuator的项目构造,工作原理进行了全面的梳理,侧重health健康检查部分
    2022-02-02
  • Java Swing仿QQ登录界面效果

    Java Swing仿QQ登录界面效果

    这篇文章主要为大家详细介绍了Java Swing仿QQ登录界面效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • 解决阿里代码规范检测中方法缺少javadoc注释的问题

    解决阿里代码规范检测中方法缺少javadoc注释的问题

    这篇文章主要介绍了解决阿里代码规范检测中方法缺少javadoc注释的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • Spring Retry 重试实例详解

    Spring Retry 重试实例详解

    这篇文章主要介绍了Spring Retry 重试,使用方式有两种分别是命令式和声明式,本文通过实例代码给大家详细讲解,需要的朋友可以参考下
    2022-10-10
  • springboot vue测试平台开发调通前后端环境实现登录

    springboot vue测试平台开发调通前后端环境实现登录

    这篇文章主要介绍了springboot vue测试平台开发调通前后端环境实现登录详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • SpringBoot实现字段自动填充的两种方式

    SpringBoot实现字段自动填充的两种方式

    每个字段在插入数据库,或者更新时都要在serviceimpl层对creatby,updateby等字段进行填充,这个太繁琐了,所以本文给大家介绍了SpringBoot实现字段自动填充的两种方式,需要的朋友可以参考下
    2024-11-11
  • Java 操作Properties配置文件详解

    Java 操作Properties配置文件详解

    这篇文章主要介绍了Java 操作Properties配置文件详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • SpringCloud分布式事务Seata部署和集成过程

    SpringCloud分布式事务Seata部署和集成过程

    这篇文章主要介绍了SpringCloud分布式事务Seata部署和集成过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-10-10

最新评论