相信很多人(包括我自己),在很长一段时间内虽然使用了JDK 1.8,却从来没有使用过自1.8开始增加的流这一强大使用的新特性,本文则将先从如何创建流开始,逐步去学会流的使用。本文不会涉及对流中数据的操作,而只讨论创建流的几种方法,以及一些基础概念,关于流的实用操作将会在后续文章中一一介绍。
<强> 1。用途与关注点不同强>
收集主要关注于对象的存储方面,通过使用<代码> 代码>列表,地图<代码> 代码>,<代码>设置> 代码等等数据结构,让数据被更好的组织起来,以便于使用。而流则关注于对象的操作方面,包含<代码>减少代码>,<代码> Map 代码>,<代码> 代码>等过滤等实用的操作。
<强> 2。流是懒搜索(Laziness-seeking)的强>
先看一个例子,考虑一下代码:
随机随机=new随机(29); random.ints () .filter (v→v比;5,,v & lt;31) .limit (3) .forEach (system . out:: println);//输出://21//22//28 >之前代码首先创建了一个随机整数流,然后过滤得到其中在(5,31)范围内的数,最终得到其中的三个数并输出,这里创建的流就是3中所说的无限流,而流在执行的过程中一旦得到一个满足条件的整数就会加到结果序列中,并且开始进行下一轮的搜索,直到找到3个满足的整数为止。流只会完成所给任务(找到3个满足指定范围的整数并输出),不会有额外的操作。
<强> 3。流的大小可以是无限的强>
尽管收集的数据量也可以动态扩展改变,但由于计算机内存是有限的,所以其数据量大小始终可以看成只能为有限的大小。但流则不同,由于流是懒加载的,所以当使用<代码> 代码>限制类似的短路操作时,就可以利用特性2的原因去接收一个无限流。
<>强4。流操作不存在副作用强>
和集合中的某些操作,例如删除会删除集合中的元素不同,流不会修改生成流的原有集合中的数据,例如使用过滤时,会产生一个经过元素过滤后的新流,而不会修改原集合中的数据。
<强> 5。流属于消耗品(消耗品)强>
不同与收集没有访问次数与使用的限制,一个流在其生命周期中只能被执行一次,当执行了终端操作(终端操作,在之后的文章中会具体介绍)后,即使没有将流关闭,例如上述代码中的forEach,也无法再次访问了(类似迭代器),如下代码所示,想要再操作,必须重新创建一个流。
IntStream流=new随机(29)相关性(); 流。过滤器(v→v比;5,,v & lt;31) .limit (3) .forEach (system . out:: println);//当执行了终端操作后再使用,就会出现一下异常提示信息//. lang。IllegalStateException:流已经进行操作或关闭 stream.forEach (system . out:: println); >之前
流可以通过很多种方式被创建,下面进行一一介绍:
<强> 1。收集家族创建的方式强>
对于实现了收集接口的类,都可以通过流()和parallelStream()创建对应流,如下代码所示:
List列表=new ArrayList<祝辞(数组。asList (1、2、3、4、5));//创建一个普通的流 Stream 流=list.stream ();//创建一个并行流 Stream parallelStream=list.parallelStream (); >之前 <强> 2。数组家族创建的方式强>
对于数组类型的元素,都可以使用数组类的<代码>流()代码>创建对应的流,如果想获得并行流则需要使用平行()<代码> 代码>方法,如下所示:
IntStream流=数组。流(新int [] {1,2,3});//生成流对应的并行流 IntStream parallelStream=stream.parallel (); >之前<强> 3.流家族的工厂方法强>
通过工厂方法来创建流的方式比较多,可以通过<代码>空代码>,<代码> 代码>,<代码> concat 代码>,<代码>生成代码>,<代码>迭代代码>,<代码> 代码>,<代码> rangeClosed> 代码以及<代码> builder> 代码等方法创建流、下面就通过代码样例来一一介绍:
//产生一个不包含任何元素的流 Stream