2014-03-30 3 views
36

Zur Zeit haben wir folgende Stream.concat in Java 8:Fehlt Java 8 ein Stream.concat, das an einem Varar von Streams arbeitet?

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

Ich bin überrascht, warum gibt es keine Version eine varargs von Stream<? extends T> zu nehmen?

Zur Zeit habe ich Code geschrieben wie:

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

Wenn ein varargs dieser Signatur verfügbar waren:

Stream<Integer> resultStream = Stream.concat(
       stream1, 
       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); 

Dann habe ich es viel deutlicher als schreiben konnte

Ohne alle verschachtelten Stream.concat Anrufe.

Oder gibt es andere Gründe, warum es nicht zur Verfügung gestellt wird?
Ich kann mir solche Gründe nicht vorstellen, da wir jetzt sowieso den Job eines Varargs Calls machen.

+0

Sie könnten durch diesen Thread gehen wollen -> http://mail.openjdk.java.net/pipermail/lambda-dev/2013-July/010647.html –

Antwort

39

Gerade flatMap es:

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()); 
} 

In Ihrem Beispiel:

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

Hinweis: Diese Lösung wird keine unendlichen Ströme abkürzen! Sehen Sie mehr hier: https://Stackoverflow.com/a/48192709/907576 – radistao

+0

Oder die [Antwort durch assylias] (https://Stackoverflow.com/a/22743697/2071828) die ich denke, ist klarer. –

+0

Nun, ich war genau durch diese Antwort verwirrt, deshalb habe ich diesen Test – radistao

25

aufgelesen von 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 erstellt. Der Post zeigt an, dass die 'flatMap'-Lösung nicht funktioniert, wenn einer der Streams unendlich ist. –

+2

Ich könnte mich in der 'flatMap' Version mit der Ausführlichkeit finden, aber diese Version scheint viel ausführlicher zu sein (Sie müssen wissen, was vor sich geht), es wird funktionieren und ist besser als 10 Streams manuell zu erstellen, sicher, aber ich tue nicht sehen, warum die Funktionalität nicht standardmäßig vorhanden ist. – skiwi

+0

@BoristheSpider Ich denke, du hast den Beitrag falsch gelesen. Es sagt 'letzteres wird scheitern, wenn s1 unendlich ist, selbst für Operationen wie findFirst', wo' letzteres 'sich auf diese Lösung bezieht. Es scheint, als wäre die 'flatMap'-Version der sichere Ansatz. – Gili

0

SO, Aggregieren Antworten of.flatMap() vs of.reduce().orElseGet(): of.flatMap nicht verarbeiten kann unendlicher Strom s, wenn of.reduce() - kann. Sehen Sie den Test Beispiel unten:

@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

Das Problem mit 'Stream.concat()' andererseits ist, dass es zu einer schlechten Performance oder 'StackOverflowError' führen kann s bei der Verarbeitung großer Mengen von Streams. Dies wird auch als Implementierungshinweis in [Javadocs] (https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#concat-java.util.stream) erwähnt. Stream-java.util.stream.Stream-). Im Grunde genommen hängt die Lösung wirklich von der Anzahl der Streams ab, die Sie verketten wollen, und wenn einer der Streams unendlich ist. – g00glen00b