关于Stream在Java8中是占非常主要的地位的,所以这次对它进行进一步探讨【这次基本上都是偏理论的东东,但是理解它很重要~】,其实流跟咱们数据库学习当中的sql语句的特点是非常非常之像的,为什么这么说,下面以这个sql语句举例说明:

select name from student where age > 20 and address = 'beijing' order by age desc;

该简单的sql所要表达的意思是:从student这张表中查询出年龄>20并且地址=北京的记录,并且对年龄进行降序排序,排序之后将其名字查找出来。对于sql其实是一个描述性的语言,只描述其行为,而具体如何让db完成这个行为是没有暴露出来的,对于该sql所做的工作如果换成咱们的stream来实现那会是个什么样子呢,下面写一下伪代码:

首先从源数据中获得stream:

students.stream();

接着进行条件过滤:age > 20 and address = 'beijing',如下:

students.stream().filter(student -> student.getAge() > 20).filter(student -> student.getAddress().equals("beijing"));

然后对年纪进行排序,这里写伪代码:

students.stream().filter(student -> student.getAge() > 20).filter(student -> student.getAddress().equals("beijing")).sorted(...);

最后将其名字打印出来,如下:
students.stream().filter(student -> student.getAge() > 20).filter(student -> student.getAddress().equals("beijing")).sorted(...).forEach(student -> System.out.println(student.getName()));

是不是从表现形式上跟sql语句差不多,Stream也是属于一种描述性的语句, 整个语句并没有告诉底层Stream要如何去做,等于只要发一些指令给底层就可以了,具体底层怎么做完全不用关心。

其实对于这种Stream()的这种方式是一种内部迭待,而如果换成传统的方式既为外部迭待方式,如下:

List<Student> list = new ArrayList<>();

//首先对数据进行条件过滤
for(int i=0; i < students.size();i++){
Student student = students.get(i);
if(student.getAge() > 20 && student.getAddress().equals("beijing")){
list.add(student);
}
} //接着对其按年龄排序
Collections.sort(list. Comparator()...); //将名字打印出来
for(Student student : list){
System.out.println(student.getName());
}

是不是发现跟使用Stream的方式完全没法相比,相差太多了,而且本质上也有区别,之所以上面传统的方式为外部迭待,很显然用到了一个中间的临时变量,另外将业务条件跟具体遍历代码都混在一起了,语义上理解也没这么容易,假如说对于一个不懂代码的人来看这两种实现方式,肯定是看具有描述性语句的stream的方式更加容易理解。

接下来用图的方式来阐述一下内部迭待与外部迭待的本质区别:

外部迭待:

针对一个集合:

以咱们这个例子为例,会使用for循环对其进行迭待,所以会单独在集合之外写入咱们自己的处理逻辑,如下:

其中集合与咱们自己编写的处理逻辑之间是有清晰的划分的:

内部迭待:

那对于stream的内部迭待方式表现又如何呢?

首先操作的对象就不是集合啦,而是集合的流,如下:

而接下来内的体现就来了,咱们自己写的代码和流会融合在一起了,而非自己写的这块代码相对于流是独立的:

合并到一起有什么好处呢?这样流就可以拿到咱们自己所提供的代码进行相应的优化,当遇到咱们调用的终止操作则将咱们提供的所有中间操作与流之前所提供好的基础功能进行统一的处理。

其实内部迭待有点像是做填充题一样,对于一篇写好的英文文章,空缺了几个填充选项【将某个单词或某个语句被扣出来了】,而咱们写的代码其实就是填补这些空缺的地方,而不是完全由自己发挥想象来写这篇英文文章;而传统的外部迭代方式则是给一个命题里面所有的内容都得由自己来编写。

另外内部迭待与外部迭待还有另外一个最大的区别,那就是内部迭待支持并行处理,而所有的并行处理其stream都已经代替咱们来处理了,也就是从调用者的角度来想就不用关心处理并行的问题,而传统的外部迭待一般都是串行的,如果也想要并行处理那这个并行的东东完全得自己来处理。

对于集合和流最后再来用一句话来概括:集合关注的是数据与数据存储本身;流关注的则是对数据的计算。而流与迭待器类似的一点是:流是无法重复使用或消费的。

另外对于流再来说明一下:对于流来说,中间操作都会返回一个Stream对象,而终止操作则不会返回Stream类型,它可能不返回值,也可能返回其它类型的单个值。所以说区分中间操作与终止操作的条件就是看返回的类型,如果是Stream对象一定是中间操作。

java8学习之内部迭代与外部迭代本质剖析及流本源分析的更多相关文章

  1. java8学习之收集器枚举特性深度解析与并行流原理

    首先先来找出上一次[http://www.cnblogs.com/webor2006/p/8353314.html]在最后举的那个并行流报错的问题,如下: 在来查找出上面异常的原因之前,当然得要一点点 ...

  2. JAVA8学习——从使用角度深入Stream流(学习过程)

    Stream 流 初识Stream流 简单认识一下Stream:Stream类中的官方介绍: /** * A sequence of elements supporting sequential an ...

  3. 初探Lambda表达式/Java多核编程【0】从外部迭代到内部迭代

    开篇 放假前从学校图书馆中借来一本书,Oracle官方的<精通Lambda表达式:Java多核编程>. 假期已过大半才想起来还没翻上几页,在此先推荐给大家. 此书内容及其简洁干练,如果你对 ...

  4. NumPy 超详细教程(3):ndarray 的内部机理及高级迭代

    系列文章地址 NumPy 最详细教程(1):NumPy 数组 NumPy 超详细教程(2):数据类型 NumPy 超详细教程(3):ndarray 的内部机理及高级迭代 ndarray 对象的内部机理 ...

  5. PythonI/O进阶学习笔记_8.python的可迭代对象和迭代器、迭代设计模式

     content: 1.什么是迭代协议 2. 什么是迭代器(Iterator)和可迭代对象(Iterable) 3. 使用迭代器和可迭代对象 4. 创建迭代器和可迭代对象 5. 迭代器设计模式   一 ...

  6. hive学习笔记之三:内部表和外部表

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  7. 大数据学习day26----hive01----1hive的简介 2 hive的安装(hive的两种连接方式,后台启动,标准输出,错误输出)3. 数据库的基本操作 4. 建表(内部表和外部表的创建以及应用场景,数据导入,学生、分数sql练习)5.分区表 6加载数据的方式

    1. hive的简介(具体见文档) Hive是分析处理结构化数据的工具   本质:将hive sql转化成MapReduce程序或者spark程序 Hive处理的数据一般存储在HDFS上,其分析数据底 ...

  8. java8学习之深入函数式接口与方法引用

    函数式接口: 函数式接口[FunctionalInterface]是整个Lambda表达式的一个根源,换句话来说java8中的Lambda表达式要想彻底掌握,前提是要彻底理解好函数式接口,所以这次继续 ...

  9. JAVA8学习——深入浅出Lambda表达式(学习过程)

    JAVA8学习--深入浅出Lambda表达式(学习过程) lambda表达式: 我们为什么要用lambda表达式 在JAVA中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法. 在 ...

随机推荐

  1. IDEA工具上传项目报:Push rejected: Push to origin/master was rejected

    原文:https://blog.csdn.net/a137151062/article/details/78820806 解决方案如下: 1.切换到自己项目所在的目录,右键选择GIT BASH Her ...

  2. golang(11) 反射用法详解

    原文链接:http://www.limerence2017.com/2019/10/14/golang16/ 反射是什么 反射其实就是通过变量动态获取其值和类型的一种技术,有些语言是支持反射的比如py ...

  3. WINDOWS mysql 5.7.15 安装配置方法图文教程

    因本人需要需要安装Mysql,现将安装过程记录如下,在自己记录的同时,希望对有疑问的人有所帮助. 一.下载软件 1. 进入mysql官网,登陆自己的oracle账号(没有账号的自己注册一个),下载My ...

  4. 【机器学习】深入理解拉格朗日乘子法(Lagrange Multiplier) 和KKT条件

    在求取有约束条件的优化问题时,拉格朗日乘子法(Lagrange Multiplier) 和KKT条件是非常重要的两个求取方法,对于等式约束的优化问题,可以应用拉格朗日乘子法去求取最优值:如果含有不等式 ...

  5. channel 介绍

    !!!1.Memory Channel 内存通道 事件将被存储在内存中的具有指定大小的队列中. 非常适合那些需要高吞吐量但是失败是会丢失数据的场景下.   属性说明: !type – 类型,必须是“m ...

  6. 强大的项目管理工具maven

    大概功能:构建项目,管理jar包,编译代码,自动运行单元测试.打包.生成报表,部署项目,生成web站点. 重要功能:依赖管理(maven对jar包的管理过程,能够大大的节约磁盘空间).项目的一键构建. ...

  7. requests-html快速入门

    昨天写了requests库好!最近requests库的作者又发布了一个新库,叫做requests-html,看名字也能猜出来,这是一个解析HTML的库,而且用起来和requests一样爽,下面就来介绍 ...

  8. Redis缓存击穿

    缓存击穿 缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞. 比如在做 ...

  9. springboot 用redis缓存整合spring cache注解,使用Json序列化和反序列化。

    springboot下用cache注解整合redis并使用json序列化反序列化. cache注解整合redis 最近发现spring的注解用起来真的是很方便.随即产生了能不能吧spring注解使用r ...

  10. priority_queue member function

    没有优先队列的dijkstra不算真的dijkstra 所以我又回来补常识了 <1>priority_queue::emplace <7>priority_queue::top ...