我发现,自从我学了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的简单小操作展示

  1. @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    class Person{
    private Integer id;
    private String name;
    private Integer age;
    private String sex;
    }
  1. /**
    * @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等等
    }

  1. /**
    * @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表达式跟方法引用的使用大家是要会的
  1. /**
    * @author Amg
    * @Description 模拟场景就是一个带重复数据的数组集合,把它转换成一个去重后的List集合并且打印List中所有元素
    * @param
    * @date 2020/9/13
    * @return void
    */
    public void testStream02(){

       Object[] array = new Object[]{1,1,1,1,1,1,2,2,2,
                                     2,2,2,3,3,3,3,3,
                                     'a','a','a','a',
                                     "e","e","e","e",
                                     3.579f,3.579f,594d,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就是去重的操作
    }
  1. /**
    * @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, sex=男), Person(id=3, name=w5, age=2, sex=男), Person(id=4, name=z6, age=13, sex=女), Person(id=5, name=t7, age=35, sex=女), Person(id=5, name=t7, age=35, sex=女)]
    1:[Person(id=1, name=z3, age=3, sex=男)]
    2:[Person(id=2, name=l4, age=4, sex=男)]
    3:[Person(id=3, name=w5, age=2, sex=男)]
    4:[Person(id=4, name=z6, age=13, sex=女)]
    5:[Person(id=5, name=t7, age=35, sex=女)]

    */
  1. /**
    * @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, 3, 4, 5, 5]
    }

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

Java8——Stream流式操作的一点小总结的更多相关文章

  1. Java8中的Stream流式操作 - 入门篇

    作者:汤圆 个人博客:javalover.cc 前言 之前总是朋友朋友的叫,感觉有套近乎的嫌疑,所以后面还是给大家改个称呼吧 因为大家是来看东西的,所以暂且叫做官人吧(灵感来自于民间流传的四大名著之一 ...

  2. Java的Stream流式操作

    前言 最近在实习,在公司看到前辈的一些代码,发现有很多值得我学习的地方,其中有一部分就是对集合使用Stream流式操作,觉得很优美且方便.所以学习一下Stream流,在这里记录一下. Stream是什 ...

  3. 《JAVA8开发指南》使用流式操作

    为什么需要流式操作 集合API是Java API中最重要的部分.基本上每一个java程序都离不开集合.尽管很重要,但是现有的集合处理在很多方面都无法满足需要. 一个原因是,许多其他的语言或者类库以声明 ...

  4. Java1.8新特性 - Stream流式算法

    一. 流式处理简介   在我接触到java8流式数据处理的时候,我的第一感觉是流式处理让集合操作变得简洁了许多,通常我们需要多行代码才能完成的操作,借助于流式处理可以在一行中实现.比如我们希望对一个包 ...

  5. 【转】Java8 Stream 流详解

      当我第一次阅读 Java8 中的 Stream API 时,说实话,我非常困惑,因为它的名字听起来与 Java I0 框架中的 InputStream 和 OutputStream 非常类似.但是 ...

  6. java1.8新特性之stream流式算法

    在Java1.8之前还没有stream流式算法的时候,我们要是在一个放有多个User对象的list集合中,将每个User对象的主键ID取出,组合成一个新的集合,首先想到的肯定是遍历,如下: List& ...

  7. 第46天学习打卡(四大函数式接口 Stream流式计算 ForkJoin 异步回调 JMM Volatile)

    小结与扩展 池的最大的大小如何去设置! 了解:IO密集型,CPU密集型:(调优)  //1.CPU密集型 几核就是几个线程 可以保持效率最高 //2.IO密集型判断你的程序中十分耗IO的线程,只要大于 ...

  8. Stream流式编程

    Stream流式编程   Stream流 说到Stream便容易想到I/O Stream,而实际上,谁规定“流”就一定是“IO流”呢?在Java 8中,得益于Lambda所带来的函数式编程,引入了一个 ...

  9. Stream流式计算

    Stream流式计算 集合/数据库用来进行数据的存储 而计算则交给流 /** * 现有5个用户,用一行代码 ,一分钟按以下条件筛选出指定用户 *1.ID必须是偶数 *2.年龄必须大于22 *3.用户名 ...

随机推荐

  1. Python中print()函数不换行的方法以及分隔符替换

    一.让print()函数不换行 在Python中,print()函数默认是换行的.但是,在很多情况下,我们需要不换行的输出(比如在算法竞赛中).那么,在Python中如何做到这一点呢? 其实很简单.只 ...

  2. Nuxt.js 踩坑记录(2) 使用sequelize时,提示install mysql2,安装了仍然不能解决问题

    打算写一个nuxt.js+sequelize+mysql的个人博客,遇到了挺多坑,还是坚持了下来,终于解决了这个bug. 今天不知道我做了什么,页面就报错了,定位到了使用sequelize的JS文件里 ...

  3. Redis+Kafka异步提高并发

    Redis+Kafka异步提高并发 Redis+Kafka异步提高并发 设计 实现 提交请求接口 Kafka消费队列 异步处理Service 客户端轮询获取结果 Redis集群节点配置 KafKa集群 ...

  4. IDEA的Debug详解

    01_Debug简介和意义 什么是程序DeBug? Debug,是程序开发人员必会的一项调试程序的技能. 企业中程序开发和程序调试的比例为1:1.5,可以说如果你不会调试程序,你就没有办法从事编程工作 ...

  5. 焦大:seo思维光年(下)seo操作如何度量化

    http://www.wocaoseo.com/thread-57-1-1.html 如果不能度量就无法进行改进,所以度量化或数据化是网站分析和网站研究必须进行的一个方面,seo也不能例外.我在上篇文 ...

  6. 这么高颜值的Kubernetes管理工具Lens,难道还不能C位出道吗

    1 前言 欢迎访问南瓜慢说 www.pkslow.com获取更多精彩文章! Docker & Kubernetes相关文章:容器技术 一直使用官方的Kubernetes Dashboard来管 ...

  7. 快速构建一个完整的Selenium框架

    今天跟大家细讲如何构建一个完整的selenium框架,当你学会了这一篇你就也可以说自己会selenium自动化测试了. 1.新建项目,结构如图: 注意:整个项目除了最外层的是文件夹,其他的都是包(pa ...

  8. 架构设计 | 基于电商交易流程,图解TCC事务分段提交

    本文源码:GitHub·点这里 || GitEE·点这里 一.场景案例简介 1.场景描述 分布式事务在业务系统中是十分常见的,最经典的场景就是电商架构中的交易业务,如图: 客户端通过请求订单服务,执行 ...

  9. MES系统与喷涂设备软件基于文本文件的数据对接方案

    产品在生产过程中除了记录产品本身的一些数据信息,往往还需要记录下生产设备的一些参数和状态,这也是MES系统的一个重要功能.客户的药物支架产品,需要用到微量药物喷涂设备,客户需要MES系统能完整记录下每 ...

  10. laravel5Eloquent模型与数据表的创建

    下面是有关管理员模型与表的创建 生成模型时同时生成数据库迁移文件 在生成的迁移文件中添加字段 运行命令行生成数据表 命令进行混合运用 生成工厂文件,数据填充文件 工厂模型代码 数据填充文件代码 数据填 ...