2014-03-30 58 views
36

目前我們已經在Java中8以下Stream.concatJava 8是否缺少一個Stream.concat工作在流的varag上?

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

我很奇怪,爲什麼沒有版本服用Stream<? extends T>一個可變參數?

目前我已經寫的代碼,如:

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調用。

或者還有其他原因爲什麼沒有提供?
我想不出這樣的理由,因爲我們現在終於做了可變參數調用的工作。

+0

你可能想通過這個話題 - > http://mail.openjdk.java.net/pipermail/lambda-dev/2013-July/010647.html –

回答

39

只是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); 
+0

注意:這個解決方案不會捷徑無限的流!在這裏看到更多:https://stackoverflow.com/a/48192709/907576 – radistao

+0

或[認爲assylias答案](https://stackoverflow.com/a/22743697/2071828),我認爲更清楚。 –

+0

好吧,我完全被這個答案困惑,這就是爲什麼我創建了這個測試 – radistao

25

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

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

+1。該帖子指出,如果其中一個流是無限的,那麼'flatMap'解決方案將不起作用。 –

+2

我可以在'flatMap'版本中找到自己的詳細信息,但是這個版本看起來更加冗長(你需要知道發生了什麼),它可以工作,並且比手動對10個流進行串接好得多,但我確實不明白爲什麼該功能默認不存在。 – skiwi

+0

@BoristheSpider我認爲你誤讀了這篇文章。它說'如果s1是無限的,那麼後者將會失敗,即使對於像findFirst這樣的操作符'後者'指的是這個解決方案。看起來''flatMap'版本實際上是安全的方法。 – Gili

0

SO,彙總答案of.flatMap() VS of.reduce().orElseGet()of.flatMap無法處理無限的流s,當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)); 
} 
} 
+0

另一方面'Stream.concat()'的問題是它可能導致性能不佳或StackOverflowError當處理大量的流時。這也在[Javadocs](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#concat-java.util.stream中的實現說明中提到。流java.util.stream.Stream-)。所以基本上,解決方案實際上取決於您試圖串聯的流的數量,以及任何流是無限的。 – g00glen00b