Stream操作整理
Stream 的特性可以归纳为:
-
不是数据结构
-
它没有内部存储,它只是用操作管道从 source(数据结构、数组、generator function、IO channel)抓取数据。
-
它也绝不修改自己所封装的底层数据结构的数据。例如 Stream 的 filter 操作会产生一个不包含被过滤元素的新 Stream,而不是从 source 删除那些元素。
-
所有 Stream 的操作必须以 lambda 表达式为参数
-
不支持索引访问
-
你可以请求第一个元素,但无法请求第二个,第三个,或最后一个。不过请参阅下一项。
-
很容易生成数组或者 List
-
惰性化
-
很多 Stream 操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始。
-
Intermediate 操作永远是惰性化的。
-
并行能力
-
当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的。
-
可以是无限的
-
集合有固定大小,Stream 则不必。limit(n) 和 findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成。
Intermediate
一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
map
1:1映射
flatMap
1:n映射
filter
distinct
sorted
对元素进行排序
比数组排序强的地方在于可以在经过map、limit。distinct等操作减少待排序元素数量之后再进行排序,也就是说要注意sorted和上述操作的执行顺序,同时这也限制了sorted能满足的需求,即先过滤后排序
时间成本nlog(n)
peek
forEach的非terminal版本
limit
返回前面n个元素
对于parallel stream而言,如果其元素有序(即在limit执行前执行sorted),那么使用limit成本会高,所以尽量不要在parallel stream使用limit或者取消元素间的顺序(不要在limit前使用sorted)
skip
丢掉前面n个元素
parallel
unordered
Terminal
一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
forEach
串行的foreach和传统的for循环几乎无性能差异
不能修改本地变量值
不能使用break/return提前结束循环
forEachOrdered
toArray
reduce
作用是吧stream元素组合起来
其提供一个起始值,然后依照运算规则和stream的第1个、第2个...第n个元素组合
当无起始值时,则把stream的第1、2个元素组合起来,返回optional
典型的操作:
求和
求最值
求平均值
字符串拼接
collect
min
时间成本O(n)
max
时间成本O(n)
count
anyMatch
allMatch
noneMatch
findFirst
返回的是optional类型
findAny
iterator
必须有limit这类的操作限制大小,和reduce很像,接受一个seed和一个f(x),
seed成为stream第一个元素,然后f(seed)是第二个,f(f(seed))是第三个
Short-circuiting
对于一个 intermediate 操作,如果它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream。
对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。
anyMatch
allMatch
findFirst
findAny
limit
collectors
辅助进行各类有用的reduce操作
网友评论