【JDK新特性】必会_Stream API

news2025/2/21 19:30:48

【必看】原创声明:转载请注明作者 & 文章来源:都在用Stream流?
​​​​​​​

hello,我是小索奇,这次讲解JDK 8新特性的重点!Stream流,到后期学习框架时候你会发现大量的Stream流出现,如果你不了解,相信索奇,你一定会再次回来的(索奇学习框架时也是..)

内容虽然很干货,但代码比较枯燥,现在不想看的可收藏备看~

Stream API

为什么要用Stream API

  • Stream流是Java 8中引入的一种新的API !importance重要 它主要是用于对集合数据进行处理的工具。Stream流可以用于对集合进行过滤、排序、映射、归约等操作,这些操作可以通过链式调用来完成,使得代码更加简洁和易于阅读。Stream流还支持并行处理,可以帮助我们更快地处理大量数据。

  • Stream流的强大之处便是在于提供了丰富的中间操作,相比集合或数组这类容器,极大的简化源数据的计算复杂度

实际开发中,项目中多数数据源都来自于MySQL、Oracle等。但现在数据源可以更多了,有MongDB,Radis等,而这些NoSQL的数据就需要Java层面去处理。

非关系型数据库(NOSQL):MongDB,Radis,采用非传统的表格结构,比如文档、键-值对、图形等,这些结构不需要使用SQL语句进行查询和操作

image-20230717001419217

image-20230717001419217

举例

比例客户端发送请求->Java后台(写SQL语句)->DB查询,结果返回给Java后台->客户端显示

对于非关系型数据库,我们可以在内存层面使用StreamAPI进行过滤

在内存层面,非关系型数据库通常采用键-值存储方式,可以直接将数据存储在内存中,这样可以大大提高数据的读取和写入速度。此外,非关系型数据库通常采用分布式架构来实现高可用性和可扩展性

使用关系型数据库进行数据过滤可能会比使用非关系型数据库慢一些,因为关系型数据库需要进行表格结构的转换和查询优化等操作。但是,关系型数据库也有其优点,比如支持事务、数据一致性等。因此,在选择数据库时,需要根据具体的应用场景和需求来进行选择。

  • Stream它主要是用于对集合数据进行处理的工具。Stream流可以用于对集合进行过滤、排序、映射、归约等操作

Stream API vs 集合框架

  • Stream API 关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU的。

  • 集合关注的数据的存储,面向内存的。

  • Stream API 之于集合,类似于SQL之于数据表的查询。

使用说明

①Stream 自己不会存储元素。

②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生结果。

④ Stream一旦执行了终止操作,就不能再调用其它中间操作或终止操作了。

Stream 执行流程

步骤1:Stream的实例化

  • 一个数据源,如集合、数组,获取一个流

步骤2:一系列的中间操作

  • 每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象。因此中间操作

    可以是个操作链,可对数据源的数据进行次处理,但是在终结操作前,并不会真正执行。

步骤3:执行终止操作(终端操作)

终止操作的方法返回值类型就不再是Stream了,因此一旦执行终止操作,就结束整个Stream操作了。一旦执行终止操作,就执行中间操

作链,最终产生结果并结束Stream。

拓展

stream方法

在Java 8中,集合类(如List、Set等)新增了一个stream()方法,可以返回一个Stream对象。Stream是一个Java 8中新增的API,用于操

作集合数据,可以实现函数式编程的方式来处理集合数据。

List的默认方法

forEach方法

forEach()是Java 8中新增的一个方法,它是Stream API的一部分,可以对集合中的每个元素执行指定的操作。forEach()方法接受一个Lambda表达式或者方法引用作为参数,Lambda表达式中定义了对每个元素要执行的操作。

下面分别用Lambda和方法引用输出,结果相同

  List<String> list2 = Arrays.asList("apple", "banana", "orange");
        System.out.println("方法引用");
        list2.forEach(System.out::println);
        System.out.println("Lambda表达式");
        list2.forEach(s-> System.out.println(s));
  • Arrays.asList() 方法可以方便地将一个数组转换为一个List集合

代码演示

员工表Employee

image-20230716222356654

image-20230716222356654

image-20230726011231112

image-20230726011231112

Stream的所有方法都给大家截了下来,见下图

image-20230726004337375

image-20230726004337375

StreamAPITest

public class StreamAPITest {

    /**
     * 创建 Stream方式一:通过集合
     */
    @Test
    public void test1(){
        List<Employee> list = EmployeeData.getEmployees();
//        default Stream<E> stream() : 返回一个顺序流
        Stream<Employee> stream = list.stream();

//        default Stream<E> parallelStream() : 返回一个并行流
        Stream<Employee> stream1 = list.parallelStream();

        System.out.println(stream);
        System.out.println(stream1);

    }

    /**
     * 创建 Stream方式二:通过数组
     */
    @Test
    public void test2(){
        //调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
        Integer[] arr = new Integer[]{1,2,3,4,5};
  // 先得到Stream的示例
        Stream<Integer> stream = Arrays.stream(arr);

        int[] arr1 = new int[]{1,2,3,4,5};
        IntStream stream1 = Arrays.stream(arr1);

    }
    /**
     * 创建 Stream方式三:通过Stream的of()
     */
    @Test
    public void test3(){
        Stream<String> stream = Stream.of("AA", "BB", "CC", "SS", "DD");
    }
}

StreamAPITest1

public class StreamAPITest01 {
    //1-筛选与切片
    @Test
    public void test1() {
//        filter(Predicate p)——接收 Lambda,从流中排除某些元素。
        //练习:查询员工表中薪资大于7000的员工信息
        List<Employee> list = EmployeeData.getEmployees();
        Stream<Employee> stream = list.stream();
        // forEach遍历是终止操作
        stream.filter(emp -> emp.getSalary() > 7000).forEach(System.out::println);

        System.out.println();
//        limit(n)——截断流,使其元素不超过给定数量。
        //这里报错,因为stream已经执行了终止操作,就不可以再调用其它的中间操作或终止操作了。要重新调用
//        stream.limit(2).forEach(System.out::println);
        list.stream().filter(emp -> emp.getSalary() > 7000).limit(2).forEach(System.out::println);

        System.out.println();
//        skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
        list.stream().skip(5).forEach(System.out::println);


        System.out.println();
//        distinct()——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
        list.add(new Employee(1009, "马斯克", 40, 12500.32));
        list.add(new Employee(1009, "马斯克", 40, 12500.32));
        list.add(new Employee(1009, "马斯克", 40, 12500.32));
        list.add(new Employee(1009, "马斯克", 40, 12500.32));

        list.stream().distinct().forEach(System.out::println);

    }

    //2-映射
    @Test
    public void test2() {
        //map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素。
        //练习:转换为大写
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
        //方式1:
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
        //方式2:
        list.stream().map(String :: toUpperCase).forEach(System.out::println);

        //练习:获取员工姓名长度大于3的员工。
        List<Employee> employees = EmployeeData.getEmployees();
        employees.stream().filter(emp -> emp.getName().length() > 3).forEach(System.out::println);

        //练习:获取员工姓名长度大于3的员工的姓名。
        //方式1:
        employees.stream().filter(emp -> emp.getName().length() > 3).map(emp -> emp.getName()).forEach(System.out::println);
        //方式2:
        employees.stream().map(emp -> emp.getName()).filter(name -> name.length() > 3).forEach(System.out::println);
        //方式3:
        employees.stream().map(Employee::getName).filter(name -> name.length() > 3).forEach(System.out::println);

    }

    //3-排序
    @Test
    public void test3() {
        //sorted()——自然排序
        Integer[] arr = new Integer[]{345,3,64,3,46,7,3,34,65,68};
        String[] arr1 = new String[]{"GG","DD","MM","SS","JJ"};

        Arrays.stream(arr).sorted().forEach(System.out::println);
        System.out.println(Arrays.toString(arr));//arr原数组并没有因为升序,做调整。

        Arrays.stream(arr1).sorted().forEach(System.out::println);

        //因为Employee没有实现Comparable接口,所以报错!使用Collections.sort()或者Arrays.sort()方法对一个对象集合进行排序时,需要使用对象的自然排序规则进行比较。而默认情况下,Java并不知道如何比较一个自定义对象的大小,因此需要我们自己定义比较规则。
//        List<Employee> list = EmployeeData.getEmployees();
//        list.stream().sorted().forEach(System.out::println);

        //sorted(Comparator com)——定制排序
        List<Employee> list = EmployeeData.getEmployees();
        list.stream().sorted((e1,e2) -> e1.getAge() - e2.getAge()).forEach(System.out::println);

        //针对于字符串从大大小排列
        Arrays.stream(arr1).sorted((s1, s2) -> -s1.compareTo(s2)).forEach(System.out::println);
//        Arrays.stream(arr1).sorted(String :: compareTo).forEach(System.out::println);
    }
}

精准练习

public class StreamAPITest2 {
    @Test
    public void test01(){
        //   boolean allMatch(Predicate<? super T> predicate);
        List<Employee> list = EmployeeData.getEmployees();
        //是否所有员工可以匹配到age>100
        System.out.println(list.stream().allMatch(employee -> employee.getAge() > 100));
        //是否存在一个员工age>99
        System.out.println(list.stream().anyMatch(employee -> employee.getAge() > 99));
        // findFirst()返回第一个元素,获取到的是第一个Optional,再调用get方法才可以获取第一个员工:
        // Employee{id=1001, name='开心', age=100, salary=666888.0}
        System.out.println(list.stream().findFirst().get());
    }
    @Test
    public void test02(){
        // count 返回流中元素的总个数
        // 返回流中工资大于1w的员工的总个数
        List<Employee> list = EmployeeData.getEmployees();
        System.out.println(list.stream().filter(employee -> employee.getSalary()>10000).count());
        // max(Comparator c) 返回流中的最大值

        // 打算获取最高工资

        //先返回最高(最低min)工资的员工
        System.out.println(list.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        //Method-1 获取到员工,在获取自身的工资即可
        System.out.println(list.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).get().getSalary());
        //Method-2  先映射工资在调用最高工资 Double.compare是返回一个int,只要返回int就行()--int compare(T o1, T o2);
        System.out.println(list.stream().map(employee -> employee.getSalary()).max((s1, s2) -> Double.compare(s1, s2)).get());
        // 改为方法引用
        System.out.println(list.stream().map(employee -> employee.getSalary()).max(Double::compare).get());

        // forEach 内部迭代
        list.stream().forEach(System.out::println);

        // 针对集合jdk8 增加一个遍历的方法 -- Iterator迭代器、增强for、一般for、ForEach
        list.forEach(System.out::println);

    }
    @Test
    public void test03(){
        /**
         * 归约操作,可以将流中元素反复结合起来,得到一个值。返回T
         */
        //T reduce(T identity, BinaryOperator<T> accumulator);
        //BinaryOperator 继承 BiFunction , 其中的方法:  R apply(T t, U u);
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        // identity 是一个累计函数的恒等值,可以把它理解为种子,在此基础上进行相加,比如10,x1+x2为55,则共65
        System.out.println(list.stream().reduce(0, (x1, x2) -> x1 + x2));
        // 改为函数式接口
        System.out.println(list.stream().reduce(0, (x1, x2) -> Integer.sum(x1,x2)));
        System.out.println(list.stream().reduce(0, Integer::sum));
        // 获取所有员工工资总和
        List<Employee> list1 = EmployeeData.getEmployees();
        // 利用reduce将所有员工工资相加
        System.out.println(list1.stream().map(emp -> emp.getSalary()).reduce((salary1, salary2) -> Double.sum(salary1, salary2)));
        System.out.println(list1.stream().map(emp -> emp.getSalary()).reduce(Double::sum));
    }
    @Test
    public void test04(){
//        collect(Collector c) 将流转换为其它形式,接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
//         练习1:查找工资大于666888的员工,结果返回为一个List或Set
        List<Employee> list = EmployeeData.getEmployees();
        List<Employee> list1 = list.stream().filter(emp -> emp.getSalary() > 666888).collect(Collectors.toList());
        list1.forEach(System.out::println);
        System.out.println("------list2------");
//      练习2:按照员工的年龄进行排序,返回到一个新的List中
        List<Employee> list2 = list.stream().sorted((e1, e2) -> e1.getAge() - e2.getAge()).collect(Collectors.toList());
        list2.forEach(System.out::println);
    }
}

索奇语录

  • 世界就像人类掌控蚂蚁、多维掌控三维一样简单而又复杂且又微妙(以前的个性签名,放到这里做个记录)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/793026.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

波奇学C++:写实拷贝,_buf数组

我们知道当自定义对象如果在堆上开空间&#xff0c;那么拷贝构造时会深拷贝&#xff0c;深拷贝会加大内存开销&#xff0c;用写实拷贝(也叫延迟拷贝)可以在深浅拷贝中取得平衡。 浅拷贝问题&#xff1a; 析构两次 一个对象修改会影响另一个 用引用计数来解决析构问题 拷贝构造时…

商品库存管理系统设计与实现(Vue+SpringBoot+MySQL)

一、项目背景 当今&#xff0c;我国科技发展日新月异&#xff0c;各类企业迅速崛起&#xff0c;商品类型日益繁多&#xff0c;产品数量急剧增加&#xff0c;企业经营模式越来越多样&#xff0c;信息处理量不断加大&#xff0c;对库存管理提出了更高的要求。通过本系统&#xff…

[详细教程+渠道对接+实战陪跑社区]抖音超火小说推文新玩法

科思创业汇 大家好&#xff0c;这里是科思创业汇&#xff0c;一个轻资产创业孵化平台。赚钱的方式有很多种&#xff0c;我希望在科思创业汇能够给你带来最快乐的那一种&#xff01; 本人为科思创业汇&#xff0c;分享网络项目案例&#xff01; 是啊&#xff0c;公益活动又来…

白话机器学习笔记(二)学习分类

分类用图形来解释&#xff0c;把他想象为有大小有方向带箭头的向量。 设权重向量为 w w w&#xff0c;虚线为使权重向量称为法线向量的直线。 直线的表达式为&#xff1a; w ⋅ x 0 w\cdot x0 w⋅x0 (两个向量的内积) 也可写为&#xff1a; w ⋅ x ∑ i 1 n w i x i w 1…

Python(基于Pyusb)与C#(基于LibUsbDotNet)USB通信速度对比

1、实验背景 项目需求&#xff1a;下位机ZYNQ&#xff0c;需设计上位机与其通信&#xff0c;通信协议USB2.0。ZYNQ端固定Buffer长度为16k&#xff0c;即上位机向ZYNQ发送任意数据&#xff0c;ZYNQ每次反馈16k长度buffer。现对Python(基于Pyusb)与C#(基于LibUsbDotNet)的USB通信…

Windows 微信更新内核(小程序框架)的指南

WMPF-PC 更新指引&#xff1a; 准备工作 1. 安装最新微信客户端&#xff08; https://dldir1.qq.com/weixin/Windows/WeChatSetup.exe &#xff09; 2. 在微信在搜索栏输入:showcmdwnd (包括前面冒号) 中输入以下代码以开启 wmpf 新内核版本(已经是现网默认&#xff0c;可以…

STM32+FPGA的导常振动信号采集存储系统

摘 要 &#xff1a; 针 对 工 厂 重 要 设 备 运 输 途 中 可 能 损 坏 的情 况 &#xff0c; 本 文 设计 了一 套 采 用 &#xff33;&#xff34;&#xff2d;&#xff13;&#xff12;&#xff26;&#xff11;&#xff10;&#xff13;&#xff0b;&#xff26;&#xff3…

2023年FPGA好就业吗?

FPGA岗位有哪些&#xff1f; 从芯片设计流程来看&#xff0c;FPGA岗位可以分四类 产品开发期&#xff1a;FPGA系统架构师 芯片设计期&#xff1a;数字IC设计工程师、FPGA开发工程师 芯片流片期&#xff1a;FPGA验证工程师 产品维护期&#xff1a;FAE工程师 从行业上来说&#x…

后端Linux软件安装大全[JDK、Tomcat、MySQL、Irzsz、Git、Maven、Redis、Nginx...持续更新中]

文章目录 前言1.软件安装方式2.安装jdk3.安装Tomcat4.安装MySQL5.安装lrzsz6. 安装Git7. 安装Maven8. 安装Redis9. 安装Nginx 总结 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&#xff0c;方便日后回顾。当然&#xff0c;如果能帮到一些萌新…

redhat官网下载7.9版本iso

redhat官方地址 https://developers.redhat.com/products/rhel/download 下载前会让你先登录&#xff0c;如果没有账号就需要先去注册账号哟。

骨传导耳机对身体有没有别的危害?骨传导耳机有什么好处?

骨传导耳机对身体有没有别的危害&#xff1f; 在此之前&#xff0c;我们先了解一下骨传导的原理&#xff1a;骨传导就跟它的名字一样通过骨头传声&#xff0c;主要是借助头部颅骨传递到听觉中枢&#xff0c;这种传播方式省略了直接接触耳道和耳膜。打个比方&#xff0c;就是我们…

Java虚拟机——前端编译优化

Java的编译期是有上下文语境影响的&#xff0c;不同语境下可以指不同的过程&#xff1a; 可以是前端编译器&#xff0c;把*.java文件转变成*.class文件的过程。 JDK的Javac、Eclipse JDT中的增量式编译器 可以指Java虚拟机的即时编译器&#xff08;JIT编译器&#xff09;在运…

json-server创建静态服务器2

上次写的 nodejs创建静态服务器 这次再来个v2.0 利用json-server很方便就可以实现。 vscode打开文件夹&#xff0c;文件夹所在终端&#xff1a; json-server.cmd --watch db.json 这里视频教程是没有上述命令标红的&#xff0c;但是会报错&#xff0c;具体不详&#xff0c…

DSSAT模型教程

详情点击链接&#xff1a;R语言与作物模型&#xff08;DSSAT模型&#xff09;教程 前言 随着基于过程的作物生长模型&#xff08;Process-based Crop Growth Simulation Model&#xff09;的发展&#xff0c;R语言在作物生长模型和数据分析、挖掘和可视化中发挥着越来越重要的…

基于 Jmeter 的轻量级云压测平台的原理与实现

目录 前言&#xff1a; 背景 云压测平台要解决什么问题 云压测平台为什么要自己实现 实现语言及内核 开发语言 Jmeter 的优缺点 Jmeter 压测启动的方式 从需求看实现 核心需求 抛弃的需求 1&#xff1a;在线生成测试脚本 抛弃的需求 2&#xff1a;在线监控服务器指…

HANA学习笔记

1、安装 准备安装介质&#xff0c;我这儿用的是HANA2.00.059.00&#xff0c;注意会用到三个lib包和saptune&#xff0c;提前准备好。 执行./hdblcm开启数据库安装&#xff0c;过程中会涉及到需要用户设置一些参数&#xff0c;按照自己需求设置即可。 安装完成会生成一个安装日…

被泼冷水后,谁能超越微服务?

历史总会重演。一切刚过去的&#xff0c;又会被重新提起。开源项目Codename One的联合创始人Shai&#xff0c;曾是Sun Microsystems开源LWUIT项目的共同作者&#xff0c;参与了无数开源项目。作为最早一批Java开发者&#xff0c;最近感慨道&#xff1a;单体&#xff0c;又回来了…

oracle查询符号隔开的字段中是否存在某项

CREATE OR REPLACE FUNCTION FIND_IN_SET_BY_COMMA(piv_str1 varchar2, piv_str2 varchar2, p_sep varchar2 : ,) -- 用什么分隔符这里改成什么 RETURN NUMBER IS l_idx number:0; -- 用于计算piv_str2中分隔符的位置 str varchar2(500); -- 根据分隔符截取的子字符串…

二、SQL-6.DCL-2).权限控制

*是数据库和表的通配符&#xff0c;出现在数据库位置上表示所有数据库&#xff0c;出现在表名位置上&#xff0c;表示所有表 %是主机名的通配符&#xff0c;表示所有主机。 e.g.所有数据库&#xff08;*&#xff09;的所有表&#xff08;*&#xff09;的所有权限&#xff08;a…

2-vi和vim的使用

vi和vim的区别 vi 是linux系统中内置的文本编辑器vim具有程序编辑能力 vi和vim常用的三种模式 正常模式 使用vim打开一个文件&#xff0c;就默认进入正常模式可以使用方向键【上下左右】来移动光标可以使用【删除字符/删除整行】来处理文件内容也可以使用【复制/粘贴】快捷键…