stream流的使用 (补充瑞吉外卖相关中的知识)
1.stream的介绍
Java8中的Stream是对容器对象功能的增强,它专注于对容器对象进行各种非常便利、高效的聚合操作,或者大批量数据操作。Stream API借助于同样新出现的Lambda表达式,极大的提高编程效率和程序可读性。同时,它提供串行(单线程)和并行(多线程)两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势。通常,编写并行代码很难而且容易出错, 但使用Stream API无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。
我们可以将流看做流水线,这个流水线是处理数据的流水线,一个产品经过流水线会有一道道的工序就如同对数据的中间操作,比如过滤我不需要的,给数据排序能,最后的终止操作就是产品从流水线下来,我们就可以统一打包放入仓库了。
当我们使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source)→ 数据转换 → 执行操作获取想要的结果。每次转换原有Stream对象不改变,返回一个新的Stream对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道:
Stream有几个特性:
Stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
Stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
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)(有重点)
因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList
、toSet
和toMap
比较常用。
下面用一个案例演示toList
、toSet
和toMap
:
@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 用得多)
映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map
和flatMap
:
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流的使用 (补充瑞吉外卖相关中的知识)相关推荐
- 瑞吉外卖项目中手机短信验证登录的问题及过程处理
瑞吉外卖中手机短信验证码登陆的问题以及过程整理 本篇接上一篇文章: <基于SpringBoot+MybatisPlus开发的外卖管理项目>戳戳戳 http://t.csdn.cn/cRJY ...
- 瑞吉外卖项目剩余功能补充
目录 菜品启售和停售 菜品批量启售和批量停售 菜品的批量删除 菜品删除逻辑优化 套餐管理的启售,停售 套餐管理的修改 后台按条件查看和展示客户订单 手机端减少购物车中的菜品或者套餐数量(前端展示有一点 ...
- 瑞吉外卖项目详细分析笔记及所有功能补充代码
目录 项目刨析简介 技术栈 项目介绍 项目源码 一.架构搭建 1.初始化项目结构 2.数据库表结构设计 3.项目基本配置信息添加 公共字段的自动填充 全局异常处理类 返回结果封装的实体类 二.管理端业 ...
- 猿创征文|瑞吉外卖——管理端_菜品管理_1
个人名片: 博主:酒徒ᝰ. 专栏:瑞吉外卖 个人简介:沉醉在酒中,借着一股酒劲,去拼搏一个未来. 本篇励志:真正的程序员不看参考手册,新手和胆小鬼才会看. 本项目基于B站黑马程序员Java项目实战&l ...
- 瑞吉外卖项目 基于spring Boot+mybatis-plus开发 超详细笔记,有源码链接
本项目是基于自学b站中 黑马程序员 的瑞吉外卖项目:视频链接: 黑马程序员Java项目实战<瑞吉外卖>,轻松掌握springboot + mybatis plus开发核心技术的真java实 ...
- 【瑞吉外卖开发笔记】
瑞吉外卖开发笔记 源码地址 一.业务开发Day01 1.软件开发整体介绍 软件开发流程 角色分工 软件环境 2.瑞奇外卖项目介绍 项目介绍 产品原型展示 技术选型 功能架构 角色 3.环境搭建 开发环 ...
- Java实战项目《瑞吉外卖》
目录 <瑞吉外卖>后台管理系统开发 软件开发整体介绍 1.软件开发流程 2.角色分工 3.软件环境 瑞吉外卖项目介绍 1.项目介绍 2.产品原型展示 3.技术选型 4.功能架构 5.角色 ...
- SB_5_瑞吉外卖_4_文件上传下载_菜品新增_菜品分页查询_菜品修改
瑞吉外卖-Day04 课程内容 文件上传下载 菜品新增 菜品分页查询 菜品修改 1. 文件上传下载 1.1 上传介绍 1.1.1 概述 文件上传,也称为upload,是指将本地图片.视频.音频等文件上 ...
- 学习 瑞吉外卖项目——总结
本文为个人学习黑马<瑞吉外卖>项目后进行的项目总结,更偏向于对自己编写文本能力的锻炼以及对项目知识点的简短记录.因为个人能力问题,其中可行性分析和测试部分只进行了小标题的陈列,并没有进行编 ...
最新文章
- display:flex弹性布局
- 同步异步单线程多线程初级理解
- 在连续发布版本的情况下 如何做好测试?
- flutter listview 滚动到指定位置_Flutter 布局原理及实战
- Per-FedAvg:联邦个性化元学习
- 【Django】基于Django架构网站代码的目录结构
- APP设计干货|切图基本知识点规范
- 微信WeixinJSBridge API 屏蔽右上角分享等常用方法
- Webb.WAVE项目开发体会与心得
- 99.9%的数据分析师,都做不到这些
- C#实现最简单的文本加密方法
- 数据可视化实战:数据可视化
- 一个元素位于另一个元素之上,点击上面的元素引发下面元素事件操作
- 共振峰估计2MATLAB
- 空间分辨率、频谱分辨率、辐射计量分辨率、时间分辨率。
- 美国单方面退出巴黎协定 可再生能源发展遇波折
- django请求生命周期,FBV和CBV,ORM拾遗,Git
- 第一章、华软代码生成器简单模板调制教程
- [听风]TBC单体插件动作条Bartender4
- ant压缩在哪卸载_如何彻底卸载流氓软件?一篇教你彻底解决!