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像素遍历详解
随机推荐
- iOS UITextField限制输入字数
关于iOS的文本框有时需要限制字数,如手机号,在UITextField的代理单纯写一个判断,在字数超过限制时,这时再想删除就删除不掉,可以在代理这样写,就解决 - (BOOL)textField:(U ...
- python界面编程
这是一个简单的加法计算器 首先,要先对这个简易计算器进行布局设计,需要两个输入框,还有一个输入框用于存放就算的结果,还需要两个table,一个是"+"一个是"=" ...
- 向指定用户发送WebSocket消息并处理对方不在线的情况
使用SimpMessagingTemplate发送消息 使用org.springframework.messaging.simp.SimpMessagingTemplate类可以在服务端的任意地方给客 ...
- JS 获取当前定位
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Oracle - 函数及多表关联
函数一般是在数据上执行的,它给数据的转换和处理提供了方便.只是将取出的数据进行处理,不会改变数据库中的值.函数根据处理的数据分为单行函数和聚合函数(组函数),组函数又被称作聚合函数,用于对多行数据进行 ...
- 洛谷P1088 火星人
//其实就是全排列 //我们从外星人给的那串数字往下搜索 //一直往下拓展m次 //最后输出结果 //虽然看起来很暴力,但是题目上说了m非常小 #include<bits/stdc++.h> ...
- PDO原生分页
** PDO分页** 1.PDO连接数据库 $dbh=new PDO('mysql:host=127.0.0.1;dbname=03a','root','root');//使用pdo 2.接收页码 $ ...
- 【openpyxl】 关于 单元格背景色 的疑惑
openpyxl 优点: 对文件进行操作, 也就是说: 如果一台电脑 没有Office excel 或 WPS excel, xlsx 是打不开的,会提示你选择程序打开. 但这时 ope ...
- 如何使用加多宝(jdb)在linux下调试Java程序
毕业时写了一段时间的C,那时候调试使用gdb,后来转了java,当时就想java程序怎么调试,找了一下,果然,那就是jdk自带的jdb windows里是这样的 Linux下是这样的 一般我在linu ...
- C - 简易贪吃蛇的编写
不多废话,直接进入正题——用C编写简易贪吃蛇.附上拙劣的源码 * c-snake * 首先说明使画面动起来的原理:通过 system("cls"); 清除当前控制台的显示,再pri ...