java8学习之Stream介绍与操作方式详解
关于默认方法【default method】的思考:
在上一次【http://www.cnblogs.com/webor2006/p/8259057.html】中对接口的默认方法进行了学习,那在Java8中在接口中接出默认方法是为了解决什么问题或者说规避什么问题呢?凡是在JDK引入一个新的概念肯定是专家们经过了一定的权衡才加入的,那加入默认方法的具体原因是啥呢?其实主要是为了解决Java8的向后兼容问题,因为毕境如今Java是一个历史非常优久且用JAVA老版本的系统也非常非常之多了,不可能因为升级到了JAVA8之后由于加入了某种新特性就造成老的系统用不了了,下面拿咱们之前使用过的List接口里面的在Java8中新加入的sort()方法来理解一下这个“向后兼容”,如下:

也就意味着在List接口中带了一个排序的功能了,那假设不是以这种默认方法的形式来提供的话【也就是将sort()方法声明为抽象的】,那么对于以前使用了List接口的代码那就会造成破坏性的影响,为什么?可以想象一样对于一个稳定的老系统当从Java的低版本升级到了Java8之后,发现List接口中多出了一个sort()抽象方法,那不得对稳定的老系统修改代码来保证可以兼容Java8,那这种设计是完全不合理的,合理的设计应该是当一个系统Java由低版本升到高版本之后应该是完全可以正常编译运行的,那么默认方法的出现就完全可以解决这样向后兼容的问题了,因为它是具体实现所以也不会使用者强制去重写里面的代码,对于老版本系统而言也无需做任何的代码变更,所以光知道默认方法是个什么东东这个不是重点,重点是要体会为啥要提出默认方法这个东东。
Stream介绍与操作方式:
关于Stream在之前的学习中也已经初步涉及到了,如下:

只是木有系统的学习,接下来就系统的对它进行了解,Stream是在Java8中与Lambda表达式相伴相生的一个极其重要的概念,通过流的方式可以让我们更好的操作集合,而且以函数式、更加流畅、更加语义化的来让我们去操作流,而流中会大量的使用到咱们之前学习的函数式接口,我们知道在Java8中函数式接口都位为java.util.function包中,而对于流则全位于java.util.stream包中,如下:

展开流包看一下:
AbstractPipeline
AbstractShortCircuitTask
AbstractSpinedBuffer
AbstractTask
BaseStream
Collector
Collectors
DistinctOps
DoublePipeline
DoubleStream
FindOps
ForEachOps
IntPipeline
IntStream
LongPipeline
LongStream
MatchOps
Node
Nodes
PipelineHelper
ReduceOps
ReferencePipeline
Sink
SliceOps
SortedOps
SpinedBuffer
Stream
StreamOpFlag
Streams
StreamShape
StreamSpliterators
StreamSupport
TerminalOp
TerminalSink
Tripwire
可以看到非常之多,当然不可能一一学到,这里跟函数式接口的学习方法类似,只学重要的,当重要的都掌握了之后,其它的就触类旁通啦,另外Stream是流中最重要的基础,如标红所示,所以接下来先学它,打开它查看一下它里面的方法,大多数是高阶函数【具体什么是高阶函数可以参考:http://www.cnblogs.com/webor2006/p/8193855.html】:

接下来读一下它的javadoc:


接着看官方对这个示例的解释:




说到pipeline,其实跟Linux的管道的概念很像,管道是将多个操作连接在一起,使得多个简单的操作最后形成一个功能非常强大的操作。


这个说明比较重要,说明了流操作的构成,这里先有个印象,之后还会再解释。

根据这段关键的说明可以对流进行一个总结:
1、流由三部份组成:
①、源;
②、零个或多个中间操作;
③、终止操作;
2、流操作的分类:
①、惰性求值;
②、及早求值;
怎么理解上面列的总结呢?其中"惰性求值"实际上就是指的"零个或多个中间操作","及早求值"指的是"终止操作",比如说有这样一个流操作:
"stream.xxx().yyy().zzz().count();",其中stream为流所对应的源,而xxx().yyy().zzz()则为中间操作,它们就是惰性求值的;而count()则为终止操作,它是及早求值的。惰性顾名思义就是比较懒惰的,如果没有终止操作它们是不会立马执行的,也就是说"stream.xxx().yyy().zzz()"这句话因为没有终止操作啥都不会执行,这就证明确实是懒性滴,而只要有了终止操作count(),那中间操作才会进行执行,而且是立即执行,并且流操作中只有一个终止操作,目前没有代码的描述可能比较抽象,有个印象既可。
流的创建:
接下来编写代码来领略一下流的使用,首先看一下如何创建一个流:

而其中看一下of()方法的定义:

接下通过数组创建,如下:

这两种其本质上是一样的,都是调用of()方法来创建。
接下来继续用第三种方式创建:

其实这种方式跟第一种的本质还是一样的,为什么?

最后再看一下最常用的创建流的方式,如下:

流的使用:
接下来具体使用一下流,看能给咱们带来哪些便利性:


编译运行:

为啥是包含了3,但是不包含8呢?看下range()的具体实现:

另外从这个例子中有木有体会到使用了Stream之后的便捷性,如果照传统的方式生成那得弄一个循环了,而使用了Stream之后一句话搞定。
那如果也想包含后面的元素呢?其实也有现成的方法,如下:

其看一下该方法的参数名就可以知晓确实是包含结束元素:

接下来用Stream来实现如下场景:有一个整形类型的List,然后对List中的每一个元素x2,然后再将所有的乘2的元素求和输出出来。传统的实现方式肯定得要遍历去实现,这里就不演示了,直接采用新的方式来写:

接着就是需要对其元素进行求和了,那怎么做呢?这时得用到reduce()了,如下:

其中第一个参数identity为初始累加值,这里当然传0啦,第二个参数为BinaryOperator,这个函数式接口咱们之前已经学习过了,回顾下它的函数原型:

而在Integer类中对于两数求和的函数刚好满足这个函数式接口的要求,看:

所以其最终的写法如下:

可见用流的方式实现是何等的清晰简单,而且语义上也更好理解,针对这个流操作,再来复习一下它的组成部分:

java8学习之Stream介绍与操作方式详解的更多相关文章
- java8学习之Stream分组与分区详解
Stream应用: 继续举例来操练Stream,对于下面这两个集合: 需求是:将这两个集合组合起来,形成对各自人员打招呼的结果,输出的结果如: "Hi zhangsan".&quo ...
- 2020你还不会Java8新特性?方法引用详解及Stream 流介绍和操作方式详解(三)
方法引用详解 方法引用: method reference 方法引用实际上是Lambda表达式的一种语法糖 我们可以将方法引用看作是一个「函数指针」,function pointer 方法引用共分为4 ...
- Java 8系列之Stream的基本语法详解
本文转至:https://blog.csdn.net/io_field/article/details/54971761 Stream系列: Java 8系列之Stream的基本语法详解 Java 8 ...
- ASP.NET MVC 5 学习教程:生成的代码详解
原文 ASP.NET MVC 5 学习教程:生成的代码详解 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 ...
- Nginx的介绍和安装详解
[介绍+安装]Nginx的介绍和安装详解 == 介绍和安装 == Nginx是一个自由.开源.高性能及轻量级的HTTP服务器及反转代理服务器, 其性能与IMAP/POP3代理服务器相当.Nginx ...
- 零拷贝详解 Java NIO学习笔记四(零拷贝详解)
转 https://blog.csdn.net/u013096088/article/details/79122671 Java NIO学习笔记四(零拷贝详解) 2018年01月21日 20:20:5 ...
- Docker学习(六)——Dockerfile文件详解
Docker学习(六)--Dockerfile文件详解 一.环境介绍 1.Dockerfile中所用的所有文件一定要和Dockerfile文件在同一级父目录下,可以为Dockerfile父目录的子目录 ...
- IP地址和子网划分学习笔记之《IP地址详解》
2018-05-03 18:47:37 在学习IP地址和子网划分前,必须对进制计数有一定了解,尤其是二进制和十进制之间的相互转换,对于我们掌握IP地址和子网的划分非常有帮助,可参看如下目录详文. ...
- OpenCV学习C++接口 Mat像素遍历详解
OpenCV学习C++接口 Mat像素遍历详解
随机推荐
- discriminator 鉴别器
在特定的情况下使用不同的pojo进行关联, 鉴别器元素就是被设计来处理这个情况的.鉴别器非常容易理解,因为它的表现很像 Java 语言中的 switch 语句:discriminator 标签常用的两 ...
- 架构模式: 健康检查API
架构模式: 健康检查API 上下文 您已应用微服务架构模式.有时,服务实例可能无法处理仍在运行的请求.例如,它可能已用完数据库连接.发生这种情况时,监控系统应生成警报.此外,负载平衡器或服务注册表不应 ...
- VS开发】如何给console控制台程序更换应用程序图标
[VS开发]如何给console控制台程序更换应用程序图标 标签:[VS开发] 实际上非常简单,就是增加一个图标资源,在资源视图里,然后修改其ID为IDC_MAINFRAME,然后编译生成即可! 20 ...
- Go语言中的打包和工具链
包 所有Go语言的程序都会组织成若干组文件,每组文件被称为一个包.这样每个包的代码都可以作为很小的复用单元,被其他项目引用. 包名惯例 给包命名的惯例是使用包所在目录的名字.并不需要所有包的名字都与别 ...
- Prometheus + Grafana 监控 Redis
Prometheus安装 .linux-amd64.tar.gz .linux-amd64. cd /prometheus # Start Prometheus. # By default, Prom ...
- 第十四周课程总结&实验报告
简单记事本的实现 实验源码 主类 package test1; import javax.swing.JFrame; import javax.swing.JTextArea; public clas ...
- Vue:不同页面之间的传递参数(二)---query
1) 在router文件下的index.js中,添加相关路径 routes: [ { path: '/', name: 'Hello', component: HelloWorld }, { path ...
- DAO语句如何定义属性类型
字体设置:代码 14px 文字 幼圆 15px public interface IAddressDAO { //添加地址 public boolean doCreate(Address addres ...
- Kefa and Dishes(CodeForces580D)【状态压缩DP】
状态压缩DP裸题,比赛的时候没反应过来,进行了n次枚举起点的solve,导致超时. #include<cstdio> #include<iostream> #include&l ...
- django form组件 cookies,session
django form组件 渲染标签 就是组件里面的字段在前端展示叫做渲染标签 校验数据 用户输入的数据提交给后端组件叫做校验数据 forms组件中定义的字段都是必须传值的(required=Tr ...