无限IntStream的长度?

时间:2018-07-18 08:27:29

标签: java random java-stream

我通过以下方式创建了randomIntStream:

 final static PrimitiveIterator.OfInt startValue = new Random().ints(0, 60).iterator();

文档说,这个流实际上是无止境的。

我想了解背景发生的事情。

ints(0,60)正在生成无限个整数流。如果这是无限的,为什么我的机器没有泄漏任何内存?

我想知道,实际上实际生成了多少个数字,并且这种实现是否会在流仍然结束的地方导致错误?还是该流会不断不断地充满新的整数,因此它真的永远不会结束吗?

如果我已经问过这个问题,那么现在最佳实践权现在是什么?

5 个答案:

答案 0 :(得分:17)

流是无限的¹,因此您可以生成任意数量的整数,而不会用完。这并不意味着它在您不要求任何内容时就不断生成它们。

实际生成多少个数字取决于您编写的代码。每次您从迭代器检索值时,都会生成一个值。不会在后台生成任何内容,因此不会使用“额外”内存。

¹就您的一生而言,请参阅伊兰的答案

答案 1 :(得分:12)

确切地说,

IntStream java.util.Random.ints(int randomNumberOrigin, int randomNumberBound)返回:

  

有效无限个伪随机整数值流,每个值均符合给定的原点(包含)和边界(不含)。

这并不意味着无限。查看Javadoc,您会看到一个实施说明,指出它实际上将返回的IntStream限制为Long.MAX_VALUE个元素:

  

实施说明:

     

此方法的实现等效于ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)

当然Long.MAX_VALUE是一个非常大的数字,因此返回的IntStream可以被视为“有效”而没有限制。例如,如果您每秒消耗该流中的1000000 int秒,则用完约292471年的时间将元素用完。

正如其他答案所述,IntStream仅产生其使用者所需的数字(即消耗int的终端操作)。

答案 2 :(得分:4)

正如@Kayaman在回答中所说。流是无限的,可以永久生成数字 。重点在于 can 一词。仅当您确实要求数字时,它才会生成数字。它不仅会生成X数量的数字,然后将它们存储在某个位置(除非您告诉它这样做)。

因此,如果要生成 n (其中n是整数)个随机数。您可以在ints(0, 60)返回的流上调用ints(n, 0, 60)Random#ints()的重载:

new Random().ints(n, 0, 60)

以上仍然不会生成 n 个随机数,因为它是IntStream,它是延迟执行的。因此,当不使用终端操作(例如collect()forEach())时,什么也没有发生。

答案 3 :(得分:4)

Streams do not (in general1) store all of their elements in any kind of a data structure:

  

没有存储空间。流不是存储元素的数据结构。相反,它通过一系列计算操作从数据结构,数组,生成器功能或I / O通道等源中传递元素。

相反,每当流前进时,就对流元素进行一对一计算。在您的示例中,调用int时实际上将计算每个随机startValue.nextInt()

例如,当我们这样做时new Random().ints(0,60),实际上是无限的流不是问题,因为在执行遍历流的操作之前,实际上不会计算出随机的int。一旦遍历流,int仅在我们请求时计算。

这是一个使用Stream.generate(也是一个无限流)的小示例,它显示了以下操作顺序:

Stream.generate(() -> {
    System.out.println("generating...");
    return "hello!";
})
.limit(3)
.forEach(elem -> {
    System.out.println(elem);
});

该代码的输出为:

generating...
hello!
generating...
hello!
generating...
hello!

请注意,我们的发电机供应商在forEach消费者每次致电之前都被致电过一次,没有更多了。如果我们不使用limit(3),则该程序可以永久运行,但不会耗尽内存。

如果我们执行了new Random().ints(0,60).forEach(...),它将以相同的方式工作。在每次调用random.nextInt(60)使用者之前,该流都会执行一次forEach。除非我们使用某些需要操作的操作,例如distinct()或收集器而不是forEach,否则元素将不会在任何地方累积。


  1. 某些流可能在后台使用数据结构进行临时存储。例如,在树遍历算法中通常使用堆栈。此外,某些流(例如使用Stream.Builder创建的流)将需要一种数据结构来放入其元素。

答案 4 :(得分:2)

创建生成器不会生成任何数字。从概念上讲,此生成器将不断生成新的数字。当询问时,它不会在任何时候不返回下一个值。