java8新特性——StreamAPI

说明:

java8中有两大最为重要的改变。第一个是Lambda表达式;另外一个则是Stream API。

Stream API(java.util.stream)把真正的函数式编程风格引入java。这是目前为止对java类库最好的补充,因为Stream API可以极大提供java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

Stream是java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用sql执行的数据库查询。也可以使用Stream API并执行操作。简言之,Stream API提供了一种高效且易于使用的处理数据的方式

 为什么使用Stream API?

实际开发中,项目中多数数据源来自于Mysql、Oracle等。但现在数据源可以更多了,有mondb,redis等,而这些NoSql的数据就需要jaav层面去处理。

 什么是Stream?

Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列

 Stream和Collection集合区别?

1.Collection是一种静态的内存数据结构,讲的是数据,而Stream是有关计算的,讲的是计算。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。

2.Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等)

3.集合关注的是数据的存储,面向内存的

 使用说明?

1.Stream自己不会存储元素。(针对数据计算)

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

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

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

 操作步骤

  1. Stream的实例化
  2. 一系列的中间操作
  3. 执行终止操作

数据准备:

创建Employee类

package data;
import com.oracle.webservices.internal.api.databinding.DatabindingMode;
public class Employee {
    private long id;
    private String name;
    private int age;
    private double salary;
    public Employee(long id,String name,int age,double salary){
        this.id = id;
        this.age = age;
        this.name = name;
        this.salary = salary;
    }
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
    @Override
    public String toString(){
        return "Employee{"+"id="+id+",name="+name+",age="+age+",salary="+salary+"}";
    }

}

创建EmployeeData类

package data;

import java.util.ArrayList;
import java.util.List;

public class EmployeeData {
    public static List<Employee> getEmployees(){
        List<Employee> list = new ArrayList<>();
        list.add(new Employee(1001,"马化腾",34,6000.38));
        list.add(new Employee(1002,"马云",2,9876.38));
        list.add(new Employee(1003,"刘强东",33,3000.82));
        list.add(new Employee(1004,"雷军",26,7657.37));
        list.add(new Employee(1005,"李彦宏",65,5555.38));
        list.add(new Employee(1006,"比尔盖茨",42,9500.38));
        list.add(new Employee(1007,"任正非",34,4333.32));
        list.add(new Employee(1008,"扎克伯格",35,2500.32));

        return list;
    }
}

1.创建Stream(三种方式)

package streamTest;

import data.Employee;
import data.EmployeeData;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class StreamAPITest {
    //创建Stream方式一:通过集合
    @Test
    public  void test1(){
        List<Employee> list = EmployeeData.getEmployees();
        //返回一个shuixu
        Stream<Employee> stream = list.stream();
        //返回一个并行流
        Stream<Employee> stream1 = list.parallelStream();
    }
    //创建Stream方式二:通过数组
    @Test
    public void test2(){
        //调用Arrays类的static<T> Stream<T> stream(T[] array):返回一个流
        Integer[] arr = new Integer[]{1,2,3,4,5};
        Stream<Integer> stream = Arrays.stream(arr);
        int[] arr1 = new int[]{1,2,3,4,5,6,7};
        IntStream stream1 = Arrays.stream(arr1);
    }
    //创建Stream方式大三:通过Stream的of()
    @Test
    public void text3(){
        Stream<String> stream = Stream.of("AA", "BB", "C");
    }
}

 2.一系列的在中间操作

1.筛选与切片

2.映射

 3.排序

1.筛选与切片

package streamTest;

import data.Employee;
import data.EmployeeData;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest1 {
    //1-筛选与切片
    @Test
    public void test(){
        //filter(Predicate p)——接收Lambda,从流中排除某些元素
       //查询员工表中薪资大于7000的员工信息
        List<Employee> list = EmployeeData.getEmployees();
        System.out.println(list);
        Stream<Employee> stream = list.stream();
        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);
        // skip(n) ——跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,返回一个空流。
        list.stream().skip(5).forEach(System.out::println);
    }
}

注意:如果stream已经执行了终止操作,不可以在调用其他的中间操作或终止操作 

2.映射

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

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

3.排序

//3-排序
    @Test
    public void test3(){
        //sorted()——自然排序
        Integer[] arr = new Integer[]{ 342,3,64,46,7,3,54,65,68};
        String[] arr1 = new String[]{"GG","DD","MM","SS","JJ"};
        Arrays.stream(arr).sorted().forEach(System.out::println);//arr数组并没有因为升序做调整
        Arrays.stream(arr1).sorted().forEach(System.out::println);//arr数组并没有因为升序做调整
        //因为Employee没有实现Comparable接口,所以报错!
//        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);
        System.out.println();
        //降序
        list.stream().sorted((e1,e2)-> e2.getAge()- e1.getAge()).forEach(System.out::println);
        //针对字符串从大到小
        Arrays.stream(arr1).sorted((s1,s2)->s2.compareTo(s1)).forEach(System.out::println);


    }

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

3.终止操作

package streamTest;

import data.Employee;
import data.EmployeeData;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 终止操作
 */
public class StreamAPITest2 {
    //1-匹配与查找
    @Test
    public void test(){
        //是否所有的员工的年龄都大于18
        //allMatch(Predicate p)——检查是否匹配所有元素
        List<Employee> list = EmployeeData.getEmployees();
        System.out.println(list.stream().allMatch(emp -> emp.getAge() > 18 ));

        //是否存在年龄大于18岁的员工
        //anyMatch(Predicate p)——检查是否至少匹配一个元素
        System.out.println(list.stream().anyMatch(emp -> emp.getAge() > 18));

        //是否存在员工的工资大于10000
        System.out.println(list.stream().anyMatch(emp -> emp.getSalary() > 10000));

        //findFirst——返回第一个元素
        System.out.println(list.stream().findFirst().get());
    }

    @Test
    public void test2(){
        List<Employee> list = EmployeeData.getEmployees();
        System.out.println(list.stream().filter(employee -> employee.getSalary()>7000).count());

        //max(Comparator c)——返回流中的最大值
        //返回最高工资的员工
        System.out.println(list.stream().max((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary())));
        //返回最低的工资
        //方式一:
        System.out.println(list.stream().max((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary())).get().getSalary());
        //方式二:
        System.out.println(list.stream().map(employee -> employee.getSalary()).max((e1,e2)->Double.compare(e1, e2)).get());

        //min(Comparator c)——返回流中的最小值
        //返回最低工资的员工
        System.out.println(list.stream().min((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary())));

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

        //针对于集合,jdk8中增加了一个遍历的方法
        list.forEach(System.out::println);
    }

    //归约
    @Test
    public void test3(){
        //reduce(T identity,BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回T
        //计算1-10的自然数的和
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        System.out.println(list.stream().reduce(0,(x1,x2)->x1+x2));
        System.out.println(list.stream().reduce(10,(x1,x2)->x1+x2));

        //reduce(BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回Optional<T>
        //计算公司所有员工工资的和
        List<Employee> employeeList = EmployeeData.getEmployees();
        System.out.println(employeeList.stream().map(emp -> emp.getSalary()).reduce((salary1, salary2) -> Double.sum(salary1, salary2)));
    }
    @Test
    public void test4(){
        //collect(Collector c)——将流转换为其他形式。接受一个Collector接口的实现,用于给Stream中的元素做汇总的方法
        //查找工资大于6000的员工,结果返回为一List或Set
        List<Employee> list = EmployeeData.getEmployees();
        List<Employee> list1 = list.stream().filter(emp -> emp.getSalary() > 6000).collect(Collectors.toList());
        list1.forEach(System.out::println);

        //按照员工的年龄进行排序,返回到一个新的List中
        System.out.println();
        List<Employee> list2 = list.stream().sorted((e1, e2) -> e1.getAge() - e2.getAge()).collect(Collectors.toList());
        list2.forEach(System.out::println);

    }
}

 总结

1.程序运行中,流Stream只能使用一次,使用后会默认关闭,不能重复使用;重复使用会报错,信息如下:

Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.AbstractPipeline.spliterator(AbstractPipeline.java:343)
    at java.util.stream.Stream.concat(Stream.java:1080)



2.在开发过程中,建议使用Stream.of(list),解决list为null的问题;使用list.stream()之前需要判断list是否为null,避免报错空指针异常(java.lang.NullPointerException)。
3.stream流遍历获取的对象是原对象
4.stream特性思维导图:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于微信小程序的在线课堂的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Codeforces Round 926 (Div. 2) B. Sasha and the Drawing (Java)

Codeforces Round 926 (Div. 2) B. Sasha and the Drawing (Java) 比赛链接&#xff1a;Codeforces Round 926 (Div. 2) B题传送门&#xff1a;B. Sasha and the Drawing 题目&#xff1a;B. Sasha and the Drawing Example input 3 4 3 3 3 10 3 9 4 7 7 11 2 3output 2 …

VMware Workstation 17.0 虚拟机安装MS-DOS 7.1完整详细步骤图文教程

VMware Workstation 17.0 虚拟机安装MS-DOS 7.1完整详细步骤图文教程 一、配置MS-DOS虚拟机机器环境二、安装MS-DOS磁盘操作系统 一、配置MS-DOS虚拟机机器环境 1.打开VMware Workstation Pro 2.新建虚拟机 3.建议选择【典型】&#xff0c;之后点击【下一步】 关于【自定义…

前端秘法基础式(CSS)(第一卷)

一.认识CSS CSS 指的是层叠样式表&#xff08;Cascading Style Sheets&#xff09;&#xff0c;它是一种用于描述网页外观和布局的语法 CSS 可以定义网页中元素的字体、颜色、大小、位置、背景等样式&#xff0c;使网页具有美观的外观和统 一的风格。 通过将 CSS 样式表与 HTML…

Qt Creator 继承分文件编写代码流程实现简单案列

Qt Creator 继承分文件流程实现简单案列 打开Qt Creator&#xff0c;新建c项目 添加类 完成之后&#xff0c;会自动生成.h和.cpp文件 一、animal.h文件 主要用来写类&#xff0c;包括成员变量和函数 #ifndef ANIMAL_H #define ANIMAL_H #include <iostream> #inclu…

C#上位机与三菱PLC的通信04--MC协议之A-1E报文测试

到目前为止&#xff0c;还没有网上有哪个文章有我如此的报文分析&#xff0c;操作实例&#xff0c;一大批都是抄来抄去&#xff0c;没有截图&#xff0c;没有说明&#xff0c;没有实例&#xff0c;有卵用呀&#xff0c;仅以此文章献给最爱的粉丝&#xff0c;希望对各位大师有些…

vue3 之 商城项目—结算模块

路由配置 chekout/index.vue <script setup> const checkInfo {} // 订单对象 const curAddress {} // 地址对象 </script> <template><div class"xtx-pay-checkout-page"><div class"container"><div class"w…

lenovo联想小新 Pro14 2022 Intel版IAH5R,AMD版ARH5R(82UT),(82UU)原装出厂Win11系统带恢复重置功能

联想小新Pro14笔记本电脑恢复原厂OEM预装Windows11系统镜像包&#xff0c;开箱状态时一模一样 Intel版(82UT)链接&#xff1a;https://pan.baidu.com/s/1jexQXkC6TerUnDQffwLooA?pwdcc09 提取码&#xff1a;cc09 AMD锐龙版(82UU)链接&#xff1a;https://pan.baidu.com/s/…

【FPGA开发】HDMI通信协议解析及FPGA实现

本篇文章包含的内容 一、HDMI简介1.1 HDMI引脚解析1.2 HDMI工作原理1.3 DVI编码1.4 TMDS编码 二、并串转换、单端差分转换原语2.1 原语简介2.2 IO端口组件 笔者在这里使用的开发板是正点原子的达芬奇开发板&#xff0c;FPGA型号为XC7A35TFGG484-2。参考的课程是正点原子的课程手…

Calendar的使用(Java)

直接从需求来理解&#xff1a;将2024年2月16日增加一个月 如果不使用Calendar的话&#xff0c;我们需要定义字符串记住这个日期&#xff0c;然后把字符串解析成Date日期对象&#xff0c;通过Date日期对象获取其毫秒值&#xff0c;然后增加一个月的毫秒值&#xff0c;再格式化时…

蓝桥杯第十四届电子类单片机组程序设计

目录 前言 蓝桥杯大赛历届真题&#xff08;点击查看&#xff09; 一、第十四届比赛题目 1.比赛原题 2.题目解读 1&#xff09;任务要求 2&#xff09;注意事项 二、任务实现 1.NE555读取时机的问题 1&#xff09;缩短计数时间 2&#xff09;实时读取 2.温度传感器读…

社区养老|社区养老服务系统|基于springboot社区养老服务系统设计与实现(源码+数据库+文档)

社区养老服务系统目录 目录 基于springboot社区养老服务系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员部分功能 &#xff08;1&#xff09; 用户管理 &#xff08;2&#xff09;服务种类管理 &#xff08;3&#xff09;社区服务管理 &#xff08…

MySQL 基础知识(八)之用户权限管理

目录 1 MySQL 权限管理概念 2 用户管理 2.1 创建用户 2.2 查看当前登录用户 2.3 修改用户名 2.4 删除用户 3 授予权限 3.1 授予用户管理员权限 3.2 授予用户数据库权限 3.3 授予用户表权限 3.4 授予用户列权限 4 查询权限 5 回收权限 1 MySQL 权限管理概念 关于 M…

NodeJS背后的人:Express

NodeJS背后的人&#xff1a;Express 本篇文章&#xff0c;学习记录于&#xff1a;尚硅谷&#x1f3a2; 文章简单学习总结&#xff1a;如有错误 大佬 &#x1f449;点. 前置知识&#xff1a;需要掌握了解&#xff1a; JavaScript基础语法 、Node.JS环境API 、前端工程\模块化 …

ESP32学习(3)——连接WIFI

1.简介 Wi-Fi是基于IEEE 802.11标准的无线网络技术 让联网设备以无线电波的形式&#xff0c;加入采用TCP/IP通信协议的网络. Wi-Fi设备有两种模式&#xff1a; 1.Access Point(AP) 模式&#xff0c;此为无线接入点&#xff0c;家里的光猫就是结合WiFi和internet路由功能的AP。…

Javaweb之SpringBootWeb案例之AOP通知类型的详细解析

3.1 通知类型 在入门程序当中&#xff0c;我们已经使用了一种功能最为强大的通知类型&#xff1a;Around环绕通知。 Around("execution(* com.itheima.service.*.*(..))") public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {//记录方法执行开始…

I/O并行口直接驱动LED显示

1&#xff0e;  实验任务 如图所示&#xff0c;利用AT89S51单片机的P0端口的P0.0&#xff0d;P0.7连接到一个共阴数码管的a&#xff0d;h的笔段上&#xff0c;数码管的公共端接地。在数码管上循环显示0&#xff0d;9数字&#xff0c;时间间隔0.2秒。 2&#xff0e;  电路原…

第7章 Page449~451 7.8.9智能指针 std::shared_ptr

“shared_ptr”是“共享式智能指针”。 即多个“shared_ptr”之间可以管理同一个裸指针。于是 O* o new O; //一个裸指针 std::shared_ptr <O> p1(o); //交给p1管 std::shared_ptr <O> p2(o); //又交给p2管 出乎意料&#xff0c;以上代码仍然是可以通过编译但运…

IO流---缓冲流,转换流,打印流,序列化流

缓冲流 缓冲流&#xff08;Buffered Stream&#xff09;也被称为高效流&#xff0c;它是对基本的字节字符流进行增强的一种流。通过缓冲流&#xff0c;可以提高数据的读写能力。 在创建缓冲流对象时&#xff0c;会创建一个内置的默认大小的缓冲区数组。通过对缓冲区的读写&…

JDBC教程+数据库连接池

JDBC 1.JDBC概述 ​ JDBC&#xff0c;全称Java数据库连接&#xff08;Java DataBase Connectivity&#xff09;&#xff0c;它是使用Java语言操作关系型数据库的一套API。 ​ JDBC本质是官方&#xff08;原SUN公司&#xff0c;现ORACLE&#xff09;定义的一套操作所有关系型数…
最新文章