java-8 streams:来自中间操作的新流是否在不增加内存的情况下返回?

时间:2016-04-01 13:21:42

标签: java java-8 java-stream

我正在努力详细了解java-8流。

来自streams上的oracle文档页面:

  

Streams在几个方面与集合不同:

     

无存储空间。流不是存储元素的数据结构;相反,它通过计算操作管道传递来自数据结构,数组,生成器函数或I / O通道等源的元素。

流操作和管道

  

流操作分为中间操作和终端操作,并组合在一起形成流管道。

流管道由源(例如Collection,数组,生成器函数或I / O通道)组成;然后是零个或多个中间操作,例如Stream.filter或Stream.map;和一个终端操作,如Stream.forEach或Stream.reduce。

  

中级操作返回新流

除了文档,我还经历了相关的SE问题:

How does streams in Java affect memory consumption?

引用的所有地方都说由于流操作的管道衬里而没有消耗额外的内存。原始流将通过管道传递。

来自Benjamin博客的一个实例:

List<String> myList =
    Arrays.asList("a1", "a2", "b1", "c2", "c1");

myList
    .stream()
    .filter(s -> s.startsWith("c"))
    .map(String::toUpperCase)
    .sorted()
    .forEach(System.out::println);

但是当像filter, map and sorted这样的中间操作返回新流时,为什么它不会增加内存消耗?我在这里错过了什么吗?

2 个答案:

答案 0 :(得分:7)

我认为你在字面上解释了文档的“无存储”部分,因为“没有内存增加”。这种解释是错误的:“无存储”意味着“没有存储流元素”。 Stream对象本身代表一个固定的开销,就像空集合有一些开销一样,因此流本身的大小不计算。

  

但是当filter,map和sorted等中间操作返回新流时,为什么不增加内存消耗呢?

确实如此。但是,尺寸的增加是固定的,即O(1)增加。这与集合形成对比,集合中n元素集合的副本增加为O(n)。

答案 1 :(得分:1)

试着在这里阅读http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html和/或http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/,我认为你想要解释的概念相当好。

基本上你可以看到的是,对于大多数中间操作,它们并不是每次操作都会同时发生。一次1个元素,它们通过所有中间操作处理,并根据终端操作丢弃或放入集合/添加到总和/打印等。如果它是一个收集类型的终端操作,那么在创建这个新集合时当然会有一些内存开销,但是在流中单独保存没有任何东西。这也是为什么你不能两次(部分)迭代流的原因。

但是有些操作,例如stream.sorted(func)在处理过程中可能需要一些状态。