import java.util.stream.*;
import java.util.*;
class TestInfiniteStream {
public static void main(String args[]) {
IntStream infiniteStream = new Random().ints();
IntStream sortedStream = infiniteStream.sorted();
sortedStream.forEach(i -> System.out.println(i));
}
}
编译并执行此代码后,出现以下错误。
Exception in thread "main" java.lang.IllegalArgumentException: Stream size exceeds max array size
在无限流上对流进行排序会失败吗?
最佳答案
“在无限流上对流进行排序会失败吗?”的简单答案是“是的。”sorted()
是一个在将任何元素传递给下游操作之前,通过缓冲整个内容并对其进行排序来实现的有状态中间操作。
理论上,它不需要那样。由于您使用的是 forEach
,它已被明确指定为以未定义的顺序处理元素,因此可以在 new Random().ints().sorted() 中省略排序步骤.forEach(System.out::println);
用例。但即使您使用了 forEachOrdered
,也有一个理论上可以实现的正确答案。由于您的流是无限的并且将重复包含所有 int
值,因此正确排序的输出将永远打印 -2147483648
(==Integer.MIN_VALUE
) ,因为这是该流中无限次包含的最小值。
但是,要给出这个正确的答案,实现需要专门的代码来处理这个场景,实用值(value)不大。相反,该实现像流场景的任何其他排序一样处理这种情况,无限流将失败。
在这种特定情况下,流具有导致不同的、不寻常的异常消息的优化。作为Eugene pointed out , 此流的行为类似于 Long.MAX_VALUE
(==2⁶³
) 元素的固定大小流,而不是真正的无限流。这是公平的,考虑到 Random
产生的流将在 2⁴⁸ 值后重复,所以整个流在结束而不是永远运行之前已经重复了 32768 次。无论如何,你不太可能在处理完 9223372036854775807 个元素后看到这个“突然”的结局。但此优化的结果是流将快速失败并显示“流大小超过最大数组大小”消息,而不是在某些处理后失败并显示“OutOfMemoryError”。
如果您删除尺寸信息,例如通过
new Random().ints().filter(x -> true).sorted().forEach(System.out::println);
该操作将尝试缓冲,直到因 java.lang.OutOfMemoryError
而失败。同样的情况发生在
IntStream.generate(new Random()::nextInt).sorted().forEach(System.out::println);
首先不向流提供大小信息。在任何一种情况下,它都不会对任何内容进行排序,因为缓冲发生在排序开始之前。
如果你想像你在评论中所说的那样“对某些元素进行排序运行”,你必须在排序之前应用一个限制,例如
new Random().ints().limit(100).sorted().forEach(System.out::println);
尽管仍然使用一定大小的流会更有效,例如
new Random().ints(100).sorted().forEach(System.out::println);
关于java - 从 Infinite Stream 派生的排序流无法迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50124348/