Java8——Stream流式操作的一点小总结

我发现,自从我学了Stream流式操作之后,工作中使用到的频率还是挺高的,因为stream配合着lambda表达式或者双冒号(::)使用真的是优雅到了极致!今天就简单分(搬)享(运)一下我对stream流式操作的一点理解

 

一、什么是流式操作?或者准确的说什么是“流”

所谓艺术来源于生活,所以不妨从一个生活中小例子展开说明一下。

通过组词,流可以组成流动,流水,流经,流进流出.... 这些描述的都是一种状态,是一种“运动”中的状态,更加通俗的讲,流水线。以往的流水线会有很多工人在,每一个工人负责一个环节,环环相联下来之后最终会形成成品。好了,现在分解一下

  1. 首先需要有一条流水线(好给你流水线)

  2. 流水线有了,那么总得需要有人在作业吧,那就放几个卡通人上去充当一下,他们将完成对原材料的筛选、清洗、组装、贴标签等操作,注意这是有顺序,这也很好理解,下一道工序必须是在上一道工序的基础上进行的,总不能跳过组装就直接装箱吧,虽然是可以,但是你发个空包给别人,真的好吗?

    所以流水线+作业人员有了

  3. 经过一番操作之后,产出产品,之后就需要打包出厂,走进寻常百姓家了。最终完整的流程就是酱紫的

 

所以,对于“流式操作”可以想象成把一项需要完成的操作“打扁”成原材料,原材料会经过经过很多道工序,而经过多道工序时的状态就是“流”,最终会对流进行一个打包收集,形成业务产品。

 

二、对于stream,你不得不了解的几个概念

第一部分通过一个简单的例子,阐述了一下先决概念,接下来就就对stream本身进行了解。

中间操作符与终止操作符

一句话讲明,中间操作符可以有多个,每个中间操作符都是在前一个中间操作符的基础上进行操作的,这就像极了刚刚讲解的多道工序,二终止操作符有且仅有一个,也即处理完所有的中间操作之后,对最终产品进行收集或者消费的,流在这里之后就会得到一个实际的“产品”。

常见的中间操作符

操作符 对应的概念
flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作 比如把 int[]{2,3,4} 拍平 变成 2,3,4 也就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,double的操作符
limit 限流操作 比如数据流中有10个 我只要出前3个就可以使用
distint 去重操作 对重复元素去重,底层使用了equals方法
filter 过滤操作 把不想要的数据过滤
peek 挑出操作 如果想对数据进行某些操作,如:读取、编辑修改等
skip 跳过操作 跳过某些元素
sorted(unordered) 排序操作 对元素排序,前提是实现Comparable接口,当然也可以自定义比较器

 

常见的终止操作符

操作符 对应的概念
collect 收集 使用系统提供的收集器可以将最终的数据流收集到List,Set,Map等容器中
count 统计操作 统计最终的数据个数
findFirst、findAny 查找操作 查找第一个、查找任何一个 返回的类型为Optional
noneMatch、allMatch、anyMatch 匹配操作 数据流中是否存在符合条件的元素 返回值为bool 值
min、max 最值操作,需要自定义比较器 返回数据流中最大最小的值
reduce 规约操作 将整个数据流的值规约为一个值,count、min、max底层就是使用reduce
forEach、forEachOrdered 遍历操作 这里就是对最终的数据进行消费了
toArray 数组操作 将数据流的元素转换成数组

 

⚠️所有的这些操作都是建立在流的基础上,所以首先需要把对象打成流,而stream主要用于对象类型的集合,当然基础类型的stream其实也是有提供的,这是打成流的方式不一致,待会会展示到底哪里不一致了。

三、stream的简单小操作展示

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
class Person{
private Integer id;
private String name;
private Integer age;
private String sex;
}
/**
* @author Amg
* @Description 首先展现一下对于对象的集合跟基本类型是怎么打成流的
* @param
* @date 2020/9/13
* @return void
*/
public void tt(){

   //基于对象的集合
   List<Person> list = new ArrayList<>();
   Stream<Person> collection = list.stream();

   //基于基本类型的
   int[] array = new int[]{1,2,3,4,5,6,7,8,9};
   IntStream primitive = Arrays.stream(array);

   //挖一下源码就会发现,其实Stream<T>跟IntStream都是继承自BaseStream的,有Int自然也会有Double、Long等等
}


/**
* @author Amg
* @Description 第二个讲一下遍历过滤输出一个给定的范围的偶数
* @param
* @date 2020/9/13
* @return void
*/
public void testStream01() {
   IntStream.range(0,20).filter(i -> (i % 2 == 0)).forEach(result -> System.out.print(result + " "));
}

//output 0 2 4 6 8 10 12 14 16 18 这里得注意了,对于lambda表达式跟方法引用的使用大家是要会的
/**
* @author Amg
* @Description 模拟场景就是一个带重复数据的数组集合,把它转换成一个去重后的List集合并且打印List中所有元素
* @param
* @date 2020/9/13
* @return void
*/
public void testStream02(){

   Object[] array = new Object[]{1,1,
                                 2,
                                 'a','a',
                                 "e","e",
                                 3.579f,3.579f,594d,
                                 97586L,97586L
                                };
   Arrays.stream(array).distinct().collect(Collectors.toList()).forEach(res-> System.out.print(res + " "));

   //output 1 2 3 a e 3.579 594.0 97586 distinct就是去重的操作
}
/**
* @author Amg
* @Description 这次模拟的场景是对对象进行操作,把list转换成map,map的键是对象的id主键,值是整个对象
* @param
* @date 2020/9/13
* @return void
*/
public void testStream03(){

   //prepareData()准备一些数据
   List<Person> list = prepareData();
   System.out.println(list);
   //Function.identify() 等价于 t -> t 返回自身
   //toMap的第三个参数可以解决冲突问题,当键值都是一致的情况,如果不添加第三个参数就会抛异常,下面的写法代表,如果有冲突则保留其中一个
   Map<Integer,Person> result = list.stream().collect(Collectors.toMap(Person -> Person.getId(),Function.identity(),(entity1,entity2)-> entity1));
   result.forEach((key,value)->{
       System.out.println(key + ":[" + value + "]");
  });
}

//output
/**  
[Person(id=1,name=z3,age=3,sex=男),Person(id=2,name=l4,age=4,Person(id=3,name=w5,age=2,Person(id=4,name=z6,age=13,sex=女),Person(id=5,name=t7,age=35,sex=女)]
1:[Person(id=1,sex=男)]
2:[Person(id=2,sex=男)]
3:[Person(id=3,sex=男)]
4:[Person(id=4,sex=女)]
5:[Person(id=5,sex=女)]

*/
/**
* @author Amg
* @Description 再考虑一个业务,从数据库中获取到对应表中指定的数据集,然后我们需要的是该表的主键id值,
* 然后通过这个主键id值去查,另外一张表的数据,得到的数据才是我们真实需要的
* @param
* @date 2020/9/13
* @return void
*/
public void testStream04(){

   //模拟环境,数据直接从方法里面模拟
   List<Person> list = getAllPersonById();

   //原操作是如此的
   List<Integer> personId = new ArrayList<>();
   for (Person person : list) {
       personId.add(person.getId());
  }

   //list里面存放的是所有的Person对象,我们将通过Stream流操作抽取出我们需要id,一行代码可以完成
   List<Integer> result = list.stream().map(Person::getId).collect(Collectors.toList());
   System.out.println(result);
   
   //output [1,2,4,5,5]
}

好了,这就是今天分享的小内容,感谢你的观看,祝你生活愉快!

 

原文地址:https://www.cnblogs.com/iamamg97

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 连接 连接池产生原因 连接池实现原理 小结 TEMPERANCE:Eat not to dullness;drink not to elevation.节制
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 一个优秀的工程师和一个普通的工程师的区别,不是满天飞的架构图,他的功底体现在所写的每一行代码上。-- 毕玄 1. 命名风格 【书摘】类名用 UpperCamelC
今天犯了个错:“接口变动,伤筋动骨,除非你确定只有你一个人在用”。哪怕只是throw了一个新的Exception。哈哈,这是我犯的错误。一、接口和抽象类类,即一个对象。先抽象类,就是抽象出类的基础部分,即抽象基类(抽象类)。官方定义让人费解,但是记忆方法是也不错的 —包含抽象方法的类叫做抽象类。接口
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket一、引子文件,作为常见的数据源。关于操作文件的字节流就是 —FileInputStream&amp;FileOutputStream。
作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节。交流QQ群:【编程之美 365234583】http://qm.qq.com/cgi-bin/qm/qr?k=FhFAoaWwjP29_Aonqz
本文目录 线程与多线程 线程的运行与创建 线程的状态 1 线程与多线程 线程是什么? 线程(Thread)是一个对象(Object)。用来干什么?Java 线程(也称 JVM 线程)是 Java 进程内允许多个同时进行的任务。该进程内并发的任务成为线程(Thread),一个进程里至少一个线程。 Ja
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket在面向对象编程中,编程人员应该在意“资源”。比如?1String hello = &quot;hello&quot;; 在代码中,我们
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 《程序兵法:Java String 源码的排序算法(一)》 文章工程:* JDK 1.8* 工程名:algorithm-core-le
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 一、父子类变量名相同会咋样? 有个小故事,今天群里面有个人问下面如图输出什么? 我回答:60。但这是错的,答案结果是 40 。我知错能改,然后说了下父子类变
作者:泥瓦匠 出处:https://www.bysocket.com/2021-10-26/mac-create-files-from-the-root-directory.html Mac 操作系统挺适合开发者进行写代码,最近碰到了一个问题,问题是如何在 macOS 根目录创建文件夹。不同的 ma
作者:李强强上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算。这一讲,泥瓦匠带你走进Java中的进制详解。一、引子在Java世界里,99%的工作都是处理这高层。那么二进制,字节码这些会在哪里用到呢?自问自答:在跨平台的时候,就凸显神功了。比如说文件读写,数据通信,还
1 线程中断 1.1 什么是线程中断? 线程中断是线程的标志位属性。而不是真正终止线程,和线程的状态无关。线程中断过程表示一个运行中的线程,通过其他线程调用了该线程的 方法,使得该线程中断标志位属性改变。 深入思考下,线程中断不是去中断了线程,恰恰是用来通知该线程应该被中断了。具体是一个标志位属性,
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want需求 项目在设计表的时候,要处理并发多的一些数据,类似订单号不能重复,要保持唯一。原本以为来个时间戳,精确到毫秒应该不错了。后来觉得是错了,测试环境下很多一
纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 加微信:bysocket01
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want.文章Points:1、介绍RESTful架构风格2、Spring配置CXF3、三层初设计,实现WebService接口层4、撰写HTTPClient 客户
Writer :BYSocket(泥沙砖瓦浆木匠)什么是回调?今天傻傻地截了张图问了下,然后被陈大牛回答道“就一个回调…”。此时千万个草泥马飞奔而过(逃哈哈,看着源码,享受着这种回调在代码上的作用,真是美哉。不妨总结总结。一、什么是回调回调,回调。要先有调用,才有调用者和被调用者之间的回调。所以在百
Writer :BYSocket(泥沙砖瓦浆木匠)一、什么大小端?大小端在计算机业界,Endian表示数据在存储器中的存放顺序。百度百科如下叙述之:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加
What is a programming language? Before introducing compilation and decompilation, let&#39;s briefly introduce the Programming Language. Programming la
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket泥瓦匠喜欢Java,文章总是扯扯Java。 I/O 基础,就是二进制,也就是Bit。一、Bit与二进制什么是Bit(位)呢?位是CPU
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocket一、前言 泥瓦匠最近被项目搞的天昏地暗。发现有些要给自己一些目标,关于技术的目标:专注很重要。专注Java 基础 + H5(学习) 其他操作系统,算法,数据结构当成课外书博览。有时候,就是那样你越是专注方面越