我正在学习Java 8中的Streams。有一个概念让我很困惑:
集合是一种内存中的数据结构,它保存着当前数据结构中所有的值——在将元素添加到集合之前,所有元素都必须先计算出来。相比之下,流是一种概念上的固定数据结构,其中的元素可以按需计算。
我不理解,如何才能使集合仅包含那些必须在添加到集合之前计算的值?此外,“流”与“固定数据结构”的比较是什么意思?
我正在学习Java 8中的Streams。有一个概念让我很困惑:
集合是一种内存中的数据结构,它保存着当前数据结构中所有的值——在将元素添加到集合之前,所有元素都必须先计算出来。相比之下,流是一种概念上的固定数据结构,其中的元素可以按需计算。
我不理解,如何才能使集合仅包含那些必须在添加到集合之前计算的值?此外,“流”与“固定数据结构”的比较是什么意思?
相比之下,流与集合在多个方面有所不同:
- 无存储。流不是存储元素的数据结构;相反,它通过计算操作管道从诸如数据结构、数组、生成器函数或 I/O 通道等源头传递元素。
- 功能性质。对流的操作会产生结果,但不会修改其源。例如,从集合获得的
Stream
进行过滤将产生一个新的没有过滤元素的Stream
,而不是从源集合中删除元素。- 延迟执行。许多流操作(例如过滤、映射或重复项删除)可以实现延迟执行,从而暴露出优化机会。例如,“查找具有三个连续元音字母的第一个字符串”无需检查所有输入字符串。流操作分为中间操作(生成流)和终端操作(产生值或副作用)。中间操作始终是延迟执行的。
- 可能无限。虽然集合具有有限大小,但流不必如此。诸如
limit(n)
或findFirst()
的短路操作可以使对无限流的计算在有限时间内完成。- 可消耗。流的元素只在流的生命周期中访问一次。与
Iterator
类似,必须生成新流才能重新访问源的相同元素。
Collection
是对象(元素)的容器。除非将对象预先添加到集合中,否则无法从集合中获取(检索)对象。size()
方法,这就是为什么我说它是“有问题的”——例如,Map
也有size()
方法,但你可以在HashMap
中拥有超过2^31个元素。将元素描述为“实际存在”的特征是哲学性的。它们也可以在实现时计算,例如通过掷骰子来确定。 - Marko Topolniksize()
返回 Integer.MAX_VALUE
。然而,当前的 HashMap
实现具有一个 int
类型大小字段,它会静默地溢出,因此它不遵循这个惯例。从这样的映射创建的流将无法报告正确的 long
类型大小,所以我认为这不是受支持的用例,而只是一个缺失的错误检测。 - HolgerCollection
和 Map
都指定了这个 Integer.MAX_VALUE
逻辑。随着 Java 堆的增长,HashMap
的不兼容性将成为一个更紧迫的问题。 - Marko Topolnik