【问题标题】:Does Java 8 lack a Stream.concat working on a varags of streams?Java 8 是否缺少处理可变流的 Stream.concat?
【发布时间】:2014-03-30 11:28:49
【问题描述】:

目前我们在 Java 8 中有以下Stream.concat

public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b);

我很惊讶为什么没有版本采用Stream&lt;? extends T&gt; 的可变参数?

目前我的代码如下:

Stream<Integer> resultStream = Stream.concat(stream1, Stream.concat(stream2, Stream.of(element)))
        .filter(x -> x != 0)
        .filter(x -> x != 1)
        .filter(x -> x != 2);

如果此签名的可变参数可用:

public static <T> Stream<T> concat(Stream<? extends T>... streams);

然后我可以更清楚地写成:

Stream<Integer> resultStream = Stream.concat(
                stream1,
                stream2,
                Stream.of(element)
        )
        .filter(x -> x != 0)
        .filter(x -> x != 1)
        .filter(x -> x != 2);

没有各种嵌套的Stream.concat 调用。

或者还有其他没有提供的原因吗?
我想不出这样的原因,因为我们现在无论如何都要完成可变参数调用的工作。

【问题讨论】:

标签: java java-8 java-stream


【解决方案1】:

flatMap吧:

public static void main(final String[] args) throws Exception {
    final Stream<String> stream1 = /*some stream*/
    final Stream<String> stream2 = /*some stream*/
    final Stream<String> stream3 = /*some stream*/
    final Stream<String> stream4 = /*some stream*/
    final Stream<String> stream5 = /*some stream*/

    final Stream<String> stream = Stream.of(stream1, stream2, stream3, stream4, stream5).flatMap(Function.identity());
}

在你的例子中:

Stream<Integer> resultStream = Stream.of(stream1, stream2, Stream.of(element))
        .flatMap(identity())
        .filter(x -> x != 0)
        .filter(x -> x != 1)
        .filter(x -> x != 2);

【讨论】:

【解决方案2】:

收集自a message in the thread linked by @RohitJain:

Stream.of(s1, s2, s3, ...)
  /* .parallel() if you want*/
  .reduce(Stream::concat)
  .orElseGet(Stream::empty);

【讨论】:

  • +1。该帖子表明,如果其中一个流是无限的,flatMap 解决方案将不起作用。
  • 我可以在flatMap 版本中找到自己的冗长,但是这个版本似乎更冗长(你需要知道发生了什么),它会工作并且比手动连接 10 更好流,当然,但我不明白为什么默认情况下该功能不存在。
  • @BoristheSpider 我认为你误读了这篇文章。它说the latter will fail if s1 is infinite even for ops like findFirst 其中latter 指的是这个解决方案。看起来flatMap 版本实际上是安全的方法。
  • 这个reduce 解决方案可以正确处理无限流,与flatMap 相反。请参阅flatMapreduce 比较:stackoverflow.com/a/48192709/907576
【解决方案3】:

在 Google Guava v21.0+ 中有:

com.google.common.collect.Streams#concat方法

【讨论】:

    【解决方案4】:

    所以,聚合答案 of.flatMap()of.reduce().orElseGet()of.flatMap 无法处理无限流,而 of.reduce() - 可以。请看下面的测试示例:

    @RunWith(JUnit4.class)
    public class StreamConcatTest {
    
    @Rule
    public Timeout globalTimeout = Timeout.seconds(3);
    
    private static final Random randomSupplier = new Random(System.currentTimeMillis());
    
    private Stream<Stream<Integer>> mergedStream;
    
    @Before
    public void setUp() throws Exception {
        Stream<Integer> infinite = Stream.concat(
                Stream.of(1, 2, 3, 4, 5),
                Stream.generate(randomSupplier::nextInt)
        );
    
        Stream<Integer> finite1 = Stream.of(100, 101, 102, 103);
        Stream<Integer> finite2 = Stream.of(222, 333, 444, 555);
    
        mergedStream = Stream.of(infinite, finite1, finite2);
    }
    
    @Test
    public void of_flatMap_FAILS_BY_TIMEOUT() throws Exception {
        Stream<Integer> streamToTest = mergedStream
                .flatMap(i -> i);
    
        assertThat(streamToTest
                        .skip(3)
                        .findFirst() // this should break infinite stream, but can't
                        .orElse(-1),
                is(4));
    }
    
    @Test
    public void of_reduce_SUCCESS() throws Exception {
        Stream<Integer> streamToTest = mergedStream
                .reduce(Stream::concat)
                .orElseGet(Stream::empty);
    
        assertThat(streamToTest
                        .skip(3)
                        .findFirst() // this really breaks infinite stream
                        .orElse(-1),
                is(4));
    }
    }
    

    【讨论】:

    • 另一方面,Stream.concat() 的问题是它在处理大量流时可能导致性能不佳或StackOverflowErrors。这在Javadocs 中也作为实现说明提到。所以基本上,解决方案实际上取决于您尝试连接的流的数量以及是否有任何流是无限的。
    • 我很困惑,这两个测试都适用于我的 java 版本:Java 11。也许它已被修复?我没有超时,所以我看不出这两种方法的区别。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-29
    • 1970-01-01
    • 2014-04-26
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    相关资源
    最近更新 更多