从Infinite Stream派生的排序流无法迭代 [英] Sorted stream derived from Infinite Stream fails to iterate

查看:92
本文介绍了从Infinite 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));
    }
}

编译并执行此代码后,我收到以下错误。

After compiling and executing this code I get the following error.

Exception in thread "main" java.lang.IllegalArgumentException: Stream size exceeds max array size

在无限流中对流进行排序是否失败?

Does sorting a stream fail on an infinite stream?

推荐答案

在无限流中对流进行排序失败吗?的简单答案是是。已排序( )是一个有状态的中间操作,它通过缓冲整个内容并对其进行排序,然后将任何元素传递给下游操作来实现。

The simple answer to "Does sorting a stream fail on an infinite stream?" is "Yes." sorted() is a stateful intermediate operation which has been implemented by buffering the entire contents and sorting it, before passing any elements to the downstream operations.

从理论上讲,它不需要那样。由于您使用 forEach ,已明确指定为以未定义的顺序处理元素,因此可在 new Random中省略排序步骤( ).ints()。sorted()。forEach(System.out :: println); 用例。但即使您使用 forEachOrdered ,理论上也可以找到正确的答案。由于您的流是无限的并且将重复包含所有 int 值,因此正确的排序输出将打印 -2147483648 == Integer.MIN_VALUE )永远,因为这是该流中无限次包含的最小值。

In theory, it doesn’t need to be that way. Since you are using forEach, which has been explicitly specified as processing the elements in an undefined order, the sorting step could be omitted in your new Random().ints().sorted().forEach(System.out::println); use case. But even if you used forEachOrdered, there is a theoretically achievable correct answer. Since your stream is infinite and will repeatedly contain all int values, a correct sorted output would print -2147483648 (==Integer.MIN_VALUE) forever, as that’s the smallest value that is contained infinite times in that stream.

但是,为了给出这个正确的答案,实现将需要特定的代码来处理这种情况,这没有多大实际价值。相反,实现处理这种情况就像流场景的任何其他排序一样,对于无限流将失败。

However, to give this correct answer, the implementation would need specific code to handle this scenario, which is of not much practical value. Instead, the implementation handles this case like any other sorting of a stream scenario, which will fail for infinite streams.

在这种特定情况下,流具有引导的优化一个不同的,不寻常的异常消息。正如 Eugene指出的那样,此流的行为类似于 Long.MAX_VALUE ==2⁶³)元素而不是真正的无限流。这是公平的,考虑到 Random 产生的流将在2⁴⁸值之后重复,因此整个流重复32768次,然后结束而不是永远运行。无论如何,在处理9223372036854775807元素之后,你不太可能目睹这种突然的结局。但是这种优化的结果是流将以流大小超过最大数组大小消息快速失败,而不是在经过一些处理后失败并出现OutOfMemoryError。

In this specific case, the stream has an optimization that leads to a different, unusual exception message. As Eugene pointed out, this stream behaves like a fixed size stream of Long.MAX_VALUE (==2⁶³) elements rather than a truly infinite stream. That’s fair, considering that the stream produced by Random will repeat after 2⁴⁸ values, so the entire stream has been repeated 32768 times before it will end instead of running forever. You are unlikely to witness this "sudden" ending after processing 9223372036854775807 elements anyway. But a consequence of this optimization is that the stream will fail-fast with the "Stream size exceeds max array size" message instead of failing with an "OutOfMemoryError" after some processing.

如果你消除了尺寸信息,例如通过

If you eliminate the size information, e.g. via

new Random().ints().filter(x -> true).sorted().forEach(System.out::println);

操作将尝试缓冲,直到失败为 java.lang.OutOfMemoryError

the operation will try to buffer until failing with java.lang.OutOfMemoryError. The same happens with

IntStream.generate(new Random()::nextInt).sorted().forEach(System.out::println);

首先不向流提供大小信息。在任何一种情况下,它都不会排序任何东西,因为在排序开始之前缓冲发生。

which provides no size information to the stream in the first place. In either case, it never gets to sort anything as the buffering happens before the sorting starts.

如果你想获得元素限制的分类运行在评论中说,你必须在排序前应用限制,例如

If you want to get "sorted runs for some limit of elements" as you said in a comment, you have to apply a limit before sorting, e.g.

new Random().ints().limit(100).sorted().forEach(System.out::println);

虽然使用大小的流会更有效,例如

though it will be more efficient to still use a sized stream, e.g.

new Random().ints(100).sorted().forEach(System.out::println);

这篇关于从Infinite Stream派生的排序流无法迭代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆