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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 携程Apollo(阿波罗)安装部署以及java整合实现

    携程Apollo(阿波罗)安装部署以及java整合实现

    这篇文章主要介绍了携程Apollo(阿波罗)安装部署以及java整合实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • Spring ApplicationContext上下文核心容器深入探究

    Spring ApplicationContext上下文核心容器深入探究

    ApplicationContext是Spring应用程序中的中央接口,由于继承了多个组件,使得ApplicationContext拥有了许多Spring的核心功能,如获取bean组件,注册监听事件,加载资源文件等
    2023-01-01
  • Mybatis迁移到Mybatis-Plus的实现方法

    Mybatis迁移到Mybatis-Plus的实现方法

    这篇文章主要介绍了Mybatis迁移到Mybatis-Plus的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • MyBatis动态创建表的实例代码

    MyBatis动态创建表的实例代码

    在项目需求中,我们经常会遇到动态操作数据表的需求,常见的我们会把日志、设备实时位置信息等存入数据表,并且以一定时间段生成一个表来存储。接下来通过本文给大家介绍MyBatis动态创建表的方法,感兴趣的朋友一起看看吧
    2018-07-07
  • SpringBoot的启动速度优化

    SpringBoot的启动速度优化

    随着我们项目的不断迭代 Bean 的数量会大大增加,如果都在启动时进行初始化会非常耗时,本文主要介绍了SpringBoot的启动速度优化,感兴趣的可以了解一下
    2023-09-09
  • springboot项目实现多数据源配置使用dynamic-datasource-spring-boot-starter的操作步骤

    springboot项目实现多数据源配置使用dynamic-datasource-spring-boot-starter

    这篇文章主要介绍了springboot项目实现多数据源配置使用dynamic-datasource-spring-boot-starter,本文分步骤结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-06-06
  • Java中String类常用方法详细汇总

    Java中String类常用方法详细汇总

    Java中String类在所有项目开发里面一定会用到,因此String类提供了一系列的功能操作方法,下面这篇文章主要给大家介绍了关于Java中String类常用方法的相关资料,需要的朋友可以参考下
    2023-05-05
  • 登录EasyConnect后无法通过jdbc访问服务器数据库问题的解决方法

    登录EasyConnect后无法通过jdbc访问服务器数据库问题的解决方法

    描述一下近期使用EasyConnect遇到的问题,下面这篇文章主要给大家介绍了关于登录EasyConnect后无法通过jdbc访问服务器数据库问题的解决方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-02-02
  • maven scope provided和runtime的例子说明

    maven scope provided和runtime的例子说明

    这篇文章主要介绍了maven scope provided和runtime的例子说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • SpringCloud环境搭建过程之Rest使用小结

    SpringCloud环境搭建过程之Rest使用小结

    这篇文章主要介绍了SpringCloud环境搭建之Rest使用,本文通过实例代码图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08

最新评论