前面有提到过lambda和函数式接口,但是JavaSE 8 除了这两个新特性之后还提供了很多有用的东西。例如Stream。
摸索了几天,终于弄明白Stream的应用了。
这里的Stream,是对集合进行操作的API。有点像流水线作业,可以一条线下来,也可以分成多条线并行。
Stream不是数据结构,而是算法和计算。所以Stream只需要被告知做什么,而不需要被告知怎么做。
举个例子,一个集合A里面有很多元素,现在想对这些元素进行操作。
传统方式:迭代器或者for循环遍历,然后对每个迭代或者遍历的元素进行操作,某种意义上说,这是有序的执行。
Stream:你只需要传入需要对元素进行的操作即可(lambda)。
【】需要告诉它做什么,不需要告诉它怎么做。例如需要统计,而不必有顺序。
步骤:①创建一个Stream;②在一个或多个步骤中,指定将初始Stream转换成另一个Stream的中间操作;③使用一个终止操作来产生一个结果。之后Stream就不可用了。
Collection接口中的新方法,可以将任何一个对象转成Stream。如果是一个数组,可以使用Stream.of()转成Stream。
还有:Stream>这种。
【】如果要对Stream中的每个对象都进行某个操作,使用【stream.map(lambda);】即可。
【】但是,如果Stream中嵌套了Stream,那就需要使用【stream.flatMap(lambda);】。这时,lambda中需要调用Stream的方法进行操作。
【】【】【】flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Stream。
Stream的limit()方法,可以截取子Stream。可以用于Stream.generate(lambda).limit(100);
Stream的聚合操作,如count()、max()、min()等,可以参照数据库的聚合函数理解。
【】【】【】需要注意的是,这些聚合函数返回的是Optional对象,可以有效避免null情况--java8推荐的操作。
Stream.reduce(),常用的方法有average, sum, min, max, and count,返回单个的结果值,并且reduce操作每处理一个元素总是创建一个新值。
//reduce()接收一个起始值(种子),然后将种子和后面的进行操作,并将结果再次作为种子。--后台方法肯定会选择一个种子(要么手动声明,要么让后台选择)
//手动声明:stream.reduce(seed, lambda) 这里的lambda只需要声明一个参数,然后能同时操作seed和该参数并返回结果即可。
//后台选择:stream.reduce(lambda) 这里的lambda需要显式的声明两个参数。后台会将stream的元素填入其中。
Stream.collect与stream.reduce方法不同,Stream.collect修改现存的值,而不是每处理一个元素,创建一个新值。
//collect需要接收三个参数(保存到什么类型的对象中、用该类型的什么方法接收、多个该类型的对象怎么联合-并行用)
//注意,①stream.collect返回的类型是保存到的类型。②Collectors中已经提供了同时具备三个参数的方法(多个方法)。
自定义stream:Stream.generate()和Stream.iterate()。
Stream.generate(Supplier)。
Stream.iterate(seed, f) 跟 reduce 操作很像,接受一个种子值,和一个 UnaryOperator(例如 f)。然后种子值成为 Stream 的第一个元素,f(seed) 为第二个,f(f(seed)) 第三个,以此类推。
【】【】如果是从Array等转成Stream,那这个Stream是有序的,但可以转成无序的。
【】【】【】【】简单说,对 Stream 的使用就是实现一个 filter-map-reduce 过程,产生一个最终结果,或者导致一个副作用(side effect)。