无限IntStream的长度?

Ann*_*ein 16 java random java-stream

我已经创建了一个randomIntStream:

 final static PrimitiveIterator.OfInt startValue = new Random().ints(0, 60).iterator();
Run Code Online (Sandbox Code Playgroud)

文档说这个流实际上是无穷无尽的.

我想了解背景中发生了什么.

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

我想知道,实际上生成了多少个数字,以及这个实现是否会在流仍然结束时导致错误?或者这个流会不断地在飞行中充满新的整数,它真的永远不会结束吗?

如果我已经提出这个问题,那么现在生成随机数的最佳做法是什么?

Kay*_*man 17

流是无限¹所以您可以生成任意数量的整数而不会耗尽.这并不意味着当你不要求它时它会继续生成它们.

实际生成了多少个数字取决于您编写的代码.每次从迭代器中检索值时,都会生成一个值.没有在后台生成,因此没有使用"额外"内存.

¹就你的一生而言,请参阅Eran的回答


Era*_*ran 12

确切地说,

IntStream java.util.Random.ints(int randomNumberOrigin, int randomNumberBound) 收益:

一个有效无限的伪随机int值流,每个值符合给定的原点(包括)和绑定(不包括).

这并不意味着无限.查看Javadoc,您将看到一个实现说明,指出它实际上限制了返回IntStreamLong.MAX_VALUE元素:

实施说明:

实现此方法等同于int(Long.MAX_VALUE,randomNumberOrigin,randomNumberBound).

当然Long.MAX_VALUE是一个非常大的数字,因此返回IntStream可以被视为"有效"无限制.例如,如果int每秒消耗该流的1000000 秒,则大约需要292471年才能耗尽元素.

也就是说,正如其他答案所提到的那样,IntStream只产生其消费者所需的数量(即消耗ints 的终端操作).


Rad*_*def 5

流不(通常1)将其所有元素存储在任何类型的数据结构中:

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

相反,每次流前进时,每个流元素都被一一计算。在您的示例中,int当您调用startValue.nextInt().

因此,当我们执行 eg 时new Random().ints(0,60),流实际上是无限的这一事实不是问题,因为int在我们执行一些遍历流的操作之前,实际上不会计算随机s。一旦我们遍历了流,ints 只会在我们请求它们时计算。

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

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

该代码的输出是:

generating...
hello!
generating...
hello!
generating...
hello!
Run Code Online (Sandbox Code Playgroud)

请注意,我们的生成器供应商在每次调用forEach消费者之前都会被调用一次,以后不会再调用了。如果我们不使用limit(3),程序可以永远运行,但不会耗尽内存。

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


  1. 一些流可能在幕后使用数据结构进行临时存储。例如,在树遍历算法期间使用堆栈是很常见的。此外,某些流(例如使用 a 创建的流)Stream.Builder需要一个数据结构来放置它们的元素。