java - 从 Infinite Stream 派生的排序流无法迭代

标签 java java-stream

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/

相关文章:

java - 多线程中的条件

java - Java泛型中的 '&'和 ','有什么区别?

java - 使用 Set<String> 和 String 作为参数创建自定义谓词

java - 如何使用java并行流代替executorThreadsPool?

Java 库 + 应用程序向 Android 设备发送推送消息

java - 为什么请求体总是空的?

java:在列表中收集和组合数据

java - 带有 Java 8 Stream 的构建器模式

Java 8 : Reverse an int array in one line (using Streams API)

java - 如何使用 Java 8 Stream/Lambda 计算整数中尾随零的数量?