1.stream的介绍

Java8中的Stream是对容器对象功能的增强,它专注于对容器对象进行各种非常便利、高效的聚合操作,或者大批量数据操作。Stream API借助于同样新出现的Lambda表达式,极大的提高编程效率和程序可读性。同时,它提供串行(单线程)和并行(多线程)两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势。通常,编写并行代码很难而且容易出错, 但使用Stream API无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。

我们可以将流看做流水线,这个流水线是处理数据的流水线,一个产品经过流水线会有一道道的工序就如同对数据的中间操作,比如过滤我不需要的,给数据排序能,最后的终止操作就是产品从流水线下来,我们就可以统一打包放入仓库了。

当我们使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source)→ 数据转换 → 执行操作获取想要的结果。每次转换原有Stream对象不改变,返回一个新的Stream对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道:

Stream有几个特性:

  1. Stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果

  2. Stream不会改变数据源,通常情况下会产生一个新的集合或一个值

  3. Stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行

2.Stream流的创建

注意:这个stream是collection的方法,所以collection的子类也都可以创建流;Map不是它的子类所以不行; 流不存放数据,所以对stream流操作进行debug也是看不到中间得操作的;

(1)Stream可以通过集合数组创建

使用集合的对象点一下,就可以发现与stream流相关的方法:

1、通过 java.util.Collection.stream() 方法用集合创建流,我们发现:

default Stream<E> stream() {return StreamSupport.stream(spliterator(), false);
}
List<String> list = Arrays.asList("a", "b", "c"); //把数组转化成集合对象
// 创建一个顺序流
Stream<String> stream = list.stream();
// 创建一个并行流
Stream<String> parallelStream = list.parallelStream();

(2)使用java.util.Arrays.stream(T[] array)方法用数组创建流

int[] array={1,3,5,6,8};
IntStream stream = Arrays.stream(array);

(3)使用Stream的静态方法:of()、iterate()、generate() 这里了解就行

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println);Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);

3.Stream的终止操作

为了方便我们后续的使用,我们先初始化一部分数据:

public class Person {private String name;  // 姓名private int salary; // 薪资private int age; // 年龄private String sex; //性别private String area;  // 地区public Person() {}public Person(String name, int salary, int age, String sex, String area) {this.name = name;this.salary = salary;this.age = age;this.sex = sex;this.area = area;}//get和set方法,tostring方法
}

初始化数据,我们设计一个简单的集合和一个复杂的集合。

后面的测试会直接使用这里构造的两个对象;

public class LambdaTest {//创建两个集合对象,后面做测试使用List<Person> personList = new ArrayList<Person>();List<Integer> simpleList = Arrays.asList(15, 22, 9, 11, 33, 52, 14);personList.add(new Person("张三",3000,23,"男","太原"));personList.add(new Person("李四",7000,34,"男","西安"));personList.add(new Person("王五",5200,22,"女","太原"));personList.add(new Person("小黑",1500,33,"女","上海"));personList.add(new Person("狗子",8000,44,"女","北京"));personList.add(new Person("铁蛋",6200,36,"女","南京"));}

①遍历/匹配(foreach/find/match)

将数据流消费掉;

@Test
public void foreachTest(){// 打印集合的元素   这里的simpleList是上面创建的集合对象,这里为了方便就分开写了simpleList.stream().forEach(System.out::println);// 其实可以简化操作的simpleList.forEach(System.out::println);
}@Test
public void findTest(){// 拿到第一个元素,后面我们学了流的排序,我们可以去取到排序中的第一个元素Optional<Integer> first = simpleList.stream().findFirst();// 随便找一个,可以看到findAny()操作,返回的元素是不确定的,// 对于同一个列表多次调用findAny()有可能会返回不同的值。// 使用findAny()是为了更高效的性能。如果是数据较少,串行地情况下,一般会返回第一个结果,// 如果是并行的情况,那就不能确保是第一个。 多线程帮你从里面任意取一个数据给你Optional<Integer> any = simpleList.parallelStream().findAny();System.out.println("first = " + first.get());System.out.println("any = " + any.get());
}@Test
public void matchTest(){// 判断有没有任意一个人年龄大于35岁  personList是前面创建的引用对象// 任意一个元素与你定义的筛选条件相匹配,那么就会返回ture给你  item是集合中的泛型对象boolean flag = personList.stream().anyMatch(item -> item.getAge() > 35);System.out.println("flag = " + flag);// 判断是不是所有人年龄都大于35岁  需要所有的元素与你定义的筛选条件相匹配,才会返回ture给你flag = personList.stream().allMatch(item -> item.getAge() > 35);System.out.println("flag = " + flag);
}

②归集(toList/toSet/toMap)(有重点)

因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toListtoSettoMap比较常用。

下面用一个案例演示toListtoSettoMap

@Test
public void collectTest(){// 判断有没有任意一个人年龄大于35岁List<Integer> collect = simpleList.stream().collect(Collectors.toList());System.out.println(collect);Set<Integer> collectSet = simpleList.stream().collect(Collectors.toSet());System.out.println(collectSet);//转换成map有许多的注意事项//第一个参数表示选择person对象中的name作为map中的key  生成的map中的key值  要使用lambda表达式获取//第二个参数表示选择集合中的泛型对象作为map的value值   生成map中的value值  要使用lambda表达式获取//第三个参数表示,如果两个map中的key相同,那么选择第一个map中对应的value值作为value值//当然你可以把自己想要的参数设置为map的key或者是value,不过记得使用lambda表示式,如果不加第三个参数那么key冲突的时候就会抛异常,key不冲突就不会Map<String, Person> collect = personList.stream().collect(Collectors.toMap(Person::getName, p -> p, (k1, k2) -> k1));System.out.println(collect);
}

③ 统计(count/average/sum/max/min)

public class StreamTest {public static void main(String[] args) {List<Integer> simpleList = Arrays.asList(15, 22, 9, 11, 33, 52, 14);//获取平均结果OptionalDouble average = simpleList.stream().mapToInt(i -> i).average();System.out.println(average);//这种写法是用来判断数据是否存在的average.ifPresent(a->{System.out.println(a);});//最大值OptionalInt max = simpleList.stream().mapToInt(i -> i).max();System.out.println(max);//求和int sum = simpleList.stream().mapToInt(i -> i).sum();System.out.println(sum);}
}

运行结果:

案例:获取员工工资的最大值:

Optional<Person> max = personList.stream().max((p1, p2) -> p1.getSalary() - p2.getSalary());
max.ifPresent(item -> System.out.println(item.getSalary()));里边的比较器可以改为:Comparator.comparingInt(Person::getSalary)

④归约(reduce)

归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

案例:求Integer集合的元素之乘积。

@Test
public void reduceTest(){List<Integer> simpleList = Arrays.asList(15, 22, 9, 11, 33, 52, 14);//n1, n2代表结果和当前的数值   这个1表示初始值,如果做加法的话那么就要设置为0,如果不传的话,那么默认是0  n1*n2 的结果会重新赋值给n1Integer result = simpleList.stream().reduce(1,(n1, n2) -> n1*n2);System.out.println(result);
}

⑤分组(partitioningBy/groupingBy)

  • 分区:将stream按条件分为两个Map,比如员工按薪资是否高于8000分为两部分。

  • 分组:将集合分为多个Map,比如员工按性别分组。

案例:

@Test
public void groupingByTest(){// 将员工按薪资是否高于5000分组  key为true的放在一个map中,key为false的放在一个map中Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 5000));// 将员工按性别分组Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));// 将员工先按性别分组,再按地区分组Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));System.out.println("员工按薪资是否大于5000分组情况:" + part);System.out.println("员工按性别分组情况:" + group);System.out.println("员工按性别、地区:" + group2);
}

 这个东西会用就行,不要去深挖里面的原理!

4.Stream中间操作

注意:我们所有的中间操作返回的值还是一个stream流,所以最后还是要进行终止操作的;

①筛选(filter 用得多)

该操作符需要传入一个function函数

List<Integer> simpleList = Arrays.asList(15, 22, 9, 11, 33, 52, 14);
//筛选出simpleList集合中大于17的元素,并打印出来
simpleList.stream().filter(item -> item > 17).forEach(System.out::println);//打印工资大于500的人  这里的personList是前面创建的一个集合对象
personList.stream().filter(p -> p.getSalary()>500).forEach(System.out::println);

筛选员工中工资高于5000的人,并形成新的集合(可以理解为在消费数据流)。

List<Person> collect = personList.stream().filter(item -> item.getSalary() > 5000).collect(Collectors.toList());
System.out.println("collect = " + collect);

②映射(map/flatMap 用得多)

映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为mapflatMap

  • map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

就是一个n1经过一系列的操作变成了n2;

  • flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

案例:将员工的薪资全部增加1000。

     List<Person> personList = new ArrayList<Person>();personList.add(new Person("张三",3000,23,"男","太原"));personList.add(new Person("李四",7000,34,"男","西安"));personList.add(new Person("王五",5200,22,"女","太原"));personList.add(new Person("小黑",1500,33,"女","上海"));personList.add(new Person("狗子",8000,44,"女","北京"));personList.add(new Person("铁蛋",6200,36,"女","南京"));List<Person> collect = personList.stream().map(item -> {item.setSalary(item.getSalary() + 1000);return item;}).collect(Collectors.toList());System.out.println(collect);

上面这种操作方式就是瑞吉外卖中经常使用到的一个操作,这个操作还可以对集合进行泛型的转换后面涉及到集合泛型的转换可以用这个来操作,非常的方便;

③排序(sorted)

sorted,中间操作。有两种排序:

  • sorted():自然排序,流中元素需实现Comparable接口

  • sorted(Comparator com):Comparator排序器自定义排序

案例:

@Test
public void sortTest(){// 按工资升序排序(自然排序)  可以自己传一个比较器,当然这里它也帮我们实现了相关的比较功能,调用相关的方法就行List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName).collect(Collectors.toList());// 按工资倒序排序List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()).map(Person::getName).collect(Collectors.toList());// 先按工资再按年龄升序排序List<String> newList3 = personList.stream().sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName).collect(Collectors.toList());// 先按工资再按年龄自定义排序(降序)List<String> newList4 = personList.stream().sorted((p1, p2) -> {if (p1.getSalary() == p2.getSalary()) {return p2.getAge() - p1.getAge();} else {return p2.getSalary() - p1.getSalary();}}).map(Person::getName).collect(Collectors.toList());System.out.println("按工资升序排序:" + newList);System.out.println("按工资降序排序:" + newList2);System.out.println("先按工资再按年龄升序排序:" + newList3);System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
}

运行结果:

其他不经常使用的操作就不一一列举了。

stream流的使用 (补充瑞吉外卖相关中的知识)相关推荐

  1. 瑞吉外卖项目中手机短信验证登录的问题及过程处理

    瑞吉外卖中手机短信验证码登陆的问题以及过程整理 本篇接上一篇文章: <基于SpringBoot+MybatisPlus开发的外卖管理项目>戳戳戳 http://t.csdn.cn/cRJY ...

  2. 瑞吉外卖项目剩余功能补充

    目录 菜品启售和停售 菜品批量启售和批量停售 菜品的批量删除 菜品删除逻辑优化 套餐管理的启售,停售 套餐管理的修改 后台按条件查看和展示客户订单 手机端减少购物车中的菜品或者套餐数量(前端展示有一点 ...

  3. 瑞吉外卖项目详细分析笔记及所有功能补充代码

    目录 项目刨析简介 技术栈 项目介绍 项目源码 一.架构搭建 1.初始化项目结构 2.数据库表结构设计 3.项目基本配置信息添加 公共字段的自动填充 全局异常处理类 返回结果封装的实体类 二.管理端业 ...

  4. 猿创征文|瑞吉外卖——管理端_菜品管理_1

    个人名片: 博主:酒徒ᝰ. 专栏:瑞吉外卖 个人简介:沉醉在酒中,借着一股酒劲,去拼搏一个未来. 本篇励志:真正的程序员不看参考手册,新手和胆小鬼才会看. 本项目基于B站黑马程序员Java项目实战&l ...

  5. 瑞吉外卖项目 基于spring Boot+mybatis-plus开发 超详细笔记,有源码链接

    本项目是基于自学b站中 黑马程序员 的瑞吉外卖项目:视频链接: 黑马程序员Java项目实战<瑞吉外卖>,轻松掌握springboot + mybatis plus开发核心技术的真java实 ...

  6. 【瑞吉外卖开发笔记】

    瑞吉外卖开发笔记 源码地址 一.业务开发Day01 1.软件开发整体介绍 软件开发流程 角色分工 软件环境 2.瑞奇外卖项目介绍 项目介绍 产品原型展示 技术选型 功能架构 角色 3.环境搭建 开发环 ...

  7. Java实战项目《瑞吉外卖》

    目录 <瑞吉外卖>后台管理系统开发 软件开发整体介绍 1.软件开发流程 2.角色分工 3.软件环境 瑞吉外卖项目介绍 1.项目介绍 2.产品原型展示 3.技术选型 4.功能架构 5.角色 ...

  8. SB_5_瑞吉外卖_4_文件上传下载_菜品新增_菜品分页查询_菜品修改

    瑞吉外卖-Day04 课程内容 文件上传下载 菜品新增 菜品分页查询 菜品修改 1. 文件上传下载 1.1 上传介绍 1.1.1 概述 文件上传,也称为upload,是指将本地图片.视频.音频等文件上 ...

  9. 学习 瑞吉外卖项目——总结

    本文为个人学习黑马<瑞吉外卖>项目后进行的项目总结,更偏向于对自己编写文本能力的锻炼以及对项目知识点的简短记录.因为个人能力问题,其中可行性分析和测试部分只进行了小标题的陈列,并没有进行编 ...

最新文章

  1. display:flex弹性布局
  2. 同步异步单线程多线程初级理解
  3. 在连续发布版本的情况下 如何做好测试?
  4. flutter listview 滚动到指定位置_Flutter 布局原理及实战
  5. Per-FedAvg:联邦个性化元学习
  6. 【Django】基于Django架构网站代码的目录结构
  7. APP设计干货|切图基本知识点规范
  8. 微信WeixinJSBridge API 屏蔽右上角分享等常用方法
  9. Webb.WAVE项目开发体会与心得
  10. 99.9%的数据分析师,都做不到这些
  11. C#实现最简单的文本加密方法
  12. 数据可视化实战:数据可视化
  13. 一个元素位于另一个元素之上,点击上面的元素引发下面元素事件操作
  14. 共振峰估计2MATLAB
  15. 空间分辨率、频谱分辨率、辐射计量分辨率、时间分辨率。
  16. 美国单方面退出巴黎协定 可再生能源发展遇波折
  17. django请求生命周期,FBV和CBV,ORM拾遗,Git
  18. 第一章、华软代码生成器简单模板调制教程
  19. [听风]TBC单体插件动作条Bartender4
  20. ant压缩在哪卸载_如何彻底卸载流氓软件?一篇教你彻底解决!

热门文章

  1. 链游、元宇宙、GameFi和NFT之间的关系
  2. 通过电脑向 Iphone 的 WPS 中传递文档
  3. 【疯壳·机器人教程3】人形街舞机器人-控制主板设计及开发环境搭建
  4. 如何用PHP/MySQL为 iOS App 写一个简单的web服务器(译) PART1
  5. 揭秘捷码运行引擎到底是如何工作的?
  6. conda中IPython无法显示图片
  7. 银杏谷资本:他们都是跑在互联网上的制造企业 | 倒计时5天
  8. 更深入到非聚集索引:通往SQL Server索引级别2的阶梯
  9. 下载钉钉直播回访视频
  10. 管理类联考——逻辑——知识篇——分析推理——四、数字——haimian