springboot3(二、StreamAPI)

这篇具有很好参考价值的文章主要介绍了springboot3(二、StreamAPI)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、StreamAPI

StreamAPI这种函数式编程是声明式编程,声明式编程是一种编程范式,它着重于描述问题的"是什么",而不是"如何做"。在声明式编程中,我们更关注问题的定义和规范,而不需要显式地指定每个步骤的实现细节。

1.介绍

Stream Pipeline:流管道、流水线
Intermediate Operations:中间提作
Terminal Operation:终止操作

Stream所有数据和操作被组合成流管道,流管道组成:

  • 一个数据源(可以是一个数组、集合、生成器函数、I/O管道)零或多个中间操作(将一个流变形成另一个流)一个终止操作(产生最终结果)
  • 流是惰性的,只有在启动最终操作时才会对源数据进行计算,而且只在需要时才会消耗源元素;

2.代码示例

获取列表中最大的偶数,示例如下:

public class StreamApi {
    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        // 获取最大偶数
        Integer max = 0;
        for (Integer i : list) {
            if (i % 2 != 0) {
                continue;
            }
            max = i >= max ? i : max;
        }
        System.out.println(max);

        /*****************************StreamAPI******************************************/
        list.stream().filter(integer -> integer % 2 == 0) //  intermediate operation
                .max(Integer::compareTo) //  terminal operation
                .ifPresent(System.out::println);
    }

}

输出:

10
10

springboot3(二、StreamAPI),springboot3,java,开发语言,spring boot
springboot3(二、StreamAPI),springboot3,java,开发语言,spring boot
总结流的三大部分:

  1. 流的数据
  2. n个中间操作
  3. 1一个终止操作

二、基本用法

1.创建流

public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Stream<Integer> stream1 = Stream.of(1,2,3);
        Stream<Integer> concatStream = Stream.concat(stream1, Stream.of(2,3,4));
        System.out.println(concatStream.toList()); // 输出:[1, 2, 3, 2, 3, 4]
        Set<Integer> set = Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        set.stream().min(Integer::compareTo).ifPresent(System.out::println);
        list.stream().min(Integer::compareTo).ifPresent(System.out::println);
}

创建流的方法有很多,代码中举了几个例子:

  • Stream.of
  • Stream.concat
  • 集合的初始化

2.流并发

下面思考两个问题:

  1. 流是并发的吗?
  2. 与for循环有哪些区别?
    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        System.out.println("主线程:"+Thread.currentThread());
        list.stream().filter(integer -> {
                    System.out.println("stream线程"+Thread.currentThread());
                    return integer % 2 == 0;
                }) //  intermediate operation
                .max(Integer::compareTo) //  terminal operation
                .ifPresent(System.out::println);
    }

输出:

主线程:Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
10

实践证明,目前的写法是没有并发的,还是在主线程中完成的。
与for循环并无区别。

但是目前我们数据量非常大,需要开并发,那么就可以使用parallel解决

    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        System.out.println("主线程:"+Thread.currentThread());
        list.stream().parallel().filter(integer -> {
                    System.out.println("stream线程"+Thread.currentThread());
                    return integer % 2 == 0;
                }) //  intermediate operation
                .max(Integer::compareTo) //  terminal operation
                .ifPresent(System.out::println);
    }

输出:

主线程:Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[main,5,main]
stream线程Thread[ForkJoinPool.commonPool-worker-1,5,main]
stream线程Thread[main,5,main]
stream线程Thread[ForkJoinPool.commonPool-worker-3,5,main]
stream线程Thread[ForkJoinPool.commonPool-worker-2,5,main]
10

注意事项:
开并发,尽可能在函数内部操作数据,避免出现安全问题。

3.流并发问题

 private static int count = 0;

    public static void main(String[] args) {
        /*****************************StreamAPI*********************************/
        System.out.println("主线程:"+Thread.currentThread());
        IntStream.range(0,100).parallel() 
                .forEach(integer -> {//  terminal operation
                    count++;
                });
        System.out.println("数据变化:"+count);
   }

看下这段代码的,由于我们写了parallel开了并发,操作的变量又是在函数外部定义的,所以是会出现安全问题的。
输出的结果可能是小于等于100的任意数字吧。
这时候一定要并发的情况下,那修改方式就是加锁,或者是换成线程安全的类型进行操作(AtomicInteger)。
代码如下:

 private static int count = 0;

    public static void main(String[] args) {
        /*****************************StreamAPI*********************************/
        System.out.println("主线程:"+Thread.currentThread());
        IntStream.range(0,100).parallel() 
                .forEach(integer -> {//  terminal operation
                    synchronized (Object.class)
                    {count++;}
                });
        System.out.println("数据变化:"+count);
   }

    public static void main(String[] args) {
        /*****************************StreamAPI******************************************/
        System.out.println("主线程:"+Thread.currentThread());
        AtomicInteger count = new AtomicInteger();
        IntStream.range(0,100).parallel() //  terminal operation
                .forEach(integer -> {
                        count.getAndIncrement();
                });
        System.out.println("数据变化:"+count);
  }

三、流方法

流的过程:每一个数据 流经 所有管道之后才会再进行下一个数据的流操作

1.中间操作

  • parallel:并发
  • filter:筛选:遍历流中的每一个元素,取出符合条件的数据
  • map:一对一处理数据,返回数据
  • peek:打印
  • sorted:排序
  • distinct:去重
  • limit:截取流中前 N 个元素
    /**
     * 中间操作测试
     *
     * @param args
     */
    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 8,9, 10);
        list.stream().limit(9)
        		.filter(integer -> {
                    System.out.println("filter输出:"+integer);
                    return integer > 4;
                })
                .peek(i -> System.out.println("peek输出:" + i))
                .map(integer -> {
                    System.out.println("map输出:"+integer);
                    return integer;
                })
                .sorted(Integer::compareTo)
                .distinct()
                .forEach(integer -> {
                    System.out.println("foreach输出:" + integer);
                });
    }

输出:

filter输出:1
filter输出:2
filter输出:3
filter输出:4
filter输出:5
peek输出:5
map输出:5
filter输出:6
peek输出:6
map输出:6
filter输出:7
peek输出:7
map输出:7
filter输出:8
peek输出:8
map输出:8
filter输出:8
peek输出:8
map输出:8
foreach输出:5
foreach输出:6
foreach输出:7
foreach输出:8

从输出中可以看到每个数据是走完整个中间流之后才会再进行下一个数据的中间操作的。

  • flatMap:一对多处理数据,返回数据
  • skip:跳过流中前 N 个元素
  • takeWhile:筛选:当满足条件,拿到这个元素,结束流循环
  /**
     * 中间操作测试
     * - flatMap:一对多处理数据,返回数据
     * - skip:跳过流中前 N 个元素
     * - takeWhile:筛选:当满足条件,拿到这个元素,结束流循环
     *
     * @param args
     */
    public static void main(String[] args) {
        List<Map<String, Object>> list = new ArrayList<>();

        list = IntStream.range(0, 10)
                .mapToObj(integer -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("name", "Bob"+integer);
                    return map;
                }).collect(Collectors.toList());
        System.out.println(list);
        //flatMap 一对多输出
        List<String> strList = list.stream()
                .skip(5)
                .flatMap(m -> Arrays.stream(m.get("name").toString().split("Bob")))
                .filter(s -> !s.isEmpty())
                .distinct()
                .toList();
        System.out.println(strList);
        List<String> strList1 = strList.stream().takeWhile(str -> 8 >= Integer.parseInt(str)).collect(Collectors.toList());
        System.out.println(strList1);

    }

输出:文章来源地址https://www.toymoban.com/news/detail-816786.html

[{name=Bob0}, {name=Bob1}, {name=Bob2}, {name=Bob3}, {name=Bob4}, {name=Bob5}, {name=Bob6}, {name=Bob7}, {name=Bob8}, {name=Bob9}]
[5, 6, 7, 8, 9]
[5, 6, 7, 8]

2.终止操作

  • foreach:对流中的每个元素执行指定操作,没有返回值。
  • max:返回最大值
  • count:返回数据总条数
  • anyMatch:判断流中是否存在满足条件的元素,如果存在则返回 true,否则返回 false。
  • collect:将流中的元素收集到一个容器中。例如,整合一个分组后的数据到容器中,collect(Collectors.groupingBy(s -> s))
  • reduce:通过累加器和初始值对流中的元素进行归约操作,返回归约后的结果。例如,可以使用 reduce(0, (a, b) -> a + b) 对整型流求和。
  • findFirst:返回流中的第一个元素(如果存在),否则返回一个空的 Optional 对象。
  • findAny:返回流中的任意一个元素(如果存在),否则返回一个空的 Optional 对象。

到了这里,关于springboot3(二、StreamAPI)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java21 + SpringBoot3使用Spring Security时如何在子线程中获取到认证信息

    目录 前言 原因分析 解决方案 方案1:手动设置线程中的认证信息 方案2:使用 DelegatingSecurityContextRunnable 创建线程 方案3:修改 Spring Security 安全策略 通过设置JVM参数修改安全策略 通过 SecurityContextHolder 修改安全策略 总结 近日心血来潮想做一个开源项目,目标是做一款可以适

    2024年02月19日
    浏览(28)
  • Java项目实战--基于SpringBoot3.0开发仿12306高并发售票系统--(一)前置知识

    本文参考自 Springboot3+微服务实战12306高性能售票系统 - 慕课网 (imooc.com) 本章将介绍仿12306售票系统实战开发的开发环境、项目核心技术和功能、项目模块和架构设计、开发所需前置知识,若想直接开始编写代码实现,请关注作者,看后面的第二章——项目实现 后端: JDK 17

    2024年04月12日
    浏览(29)
  • JAVA新实战1:使用vscode+gradle+openJDK21搭建java springboot3项目开发环境

            作为一个干了多年的全栈技术工程师,厌倦了使用盗版IDE,近些年开发Java一直使用IntelliJ IDEA进行Springboot后端项目开发,对于IntelliJ IDEA 授权问题,一直花钱买学生类的授权,但经常被屏蔽,无法使用,又不舍得花大钱买企业版,索性不再使用了。决定改用 VsCode+Gr

    2024年02月03日
    浏览(53)
  • Java项目实战笔记--基于SpringBoot3.0开发仿12306高并发售票系统--(二)项目实现-第二篇-前端模块搭建及单点登录的实现

    本文参考自 Springboot3+微服务实战12306高性能售票系统 - 慕课网 (imooc.com) 本文是仿12306项目实战第(二)章——项目实现 的第二篇,详细讲解使用Vue3 + Vue CLI 实现前端模块搭建的过程,同时其中也会涉及一些前后端交互的实现,因此也会开发一些后端接口;搭建好前端页面后,

    2024年03月26日
    浏览(43)
  • Java Spring Boot 开发框架

    Spring Boot是一种基于Java编程语言的开发框架,它的目标是简化Java应用程序的开发过程。Spring Boot提供了一种快速、易于使用的方式来创建独立的、生产级别的Java应用程序。本文将介绍Spring Boot的特性、优势以及如何使用它来开发高效、可靠的应用程序。 Spring Boot是由Pivotal团队

    2024年02月08日
    浏览(40)
  • 【SpringBoot3】从重构HelloWorld看Spring的作用

    在我们学习一门新技术的时候,总是先运行出一个基本的程序来输出“Hello World”,如果成功了, 说明我们的开发环境基本就绪了,我们也像婴儿走路一样,能走第一步了。接下来我们就逐步改造一个最基本的HelloWorld来一步步分析Spring到底帮助我们做 了什么。 目录 第一步:

    2024年02月19日
    浏览(30)
  • “深入解析Spring Boot:快速开发Java应用的利器“

    标题:深入解析Spring Boot:快速开发Java应用的利器 摘要:Spring Boot是一个开发Java应用的利器,它简化了Spring应用的配置和部署过程,提供了快速构建和开发Java应用的能力。本文将深入解析Spring Boot的核心特性和优势,并通过示例代码来展示如何使用Spring Boot进行快速应用开发

    2024年02月16日
    浏览(36)
  • Java 中 Spring Boot 框架下的 Email 开发

    hutool工具包: 这个类更贴近我们的常见信息 ,用这个去构造邮箱框架的指定邮件类的构造。 邮箱格式检查: 以 yeah.net 邮箱为例(其他的邮箱也会有,举一反三) 根据指导即可,获得授权密码! 以smtp为例: 这个就是host,可以查一下,port是465(其他的服务器 port是啥,一查

    2024年04月08日
    浏览(40)
  • 【Spring Cloud Gateway】⑥SpringBoot3.x集成SpringDoc指南

    Spring Cloud Gateway 使用 Netty 作为嵌入式服务器,并基于响应式 Spring WebFlux 。做为微服务网关,多个微服务把 API 挂在 Gateway 上,如果查看某个 API 的 Swagger 还要去各个子微服务中去查看,就很不方便,如果能在 Gateway 上直接查看各个微服务的 API 文档,会方便很多,本文以截至

    2024年02月14日
    浏览(37)
  • 【Java开发】 Spring 11 :Spring Boot 项目部署至云服务器

    Spring Boot 项目开发结束后的工作便是运维,简单来说需要配置 Web 运行参数和项目部署两大工作,本文将尽可能详细地给大家讲全! 目录 1 定制 Web 容器运行参数 1.1 运行参数介绍 1.2 项目搭建 ① 通过 IDEA Spring Initializr 创建项目 ② 添加 Spring Web 等依赖 ③ 编写 controller 层的

    2023年04月23日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包