Zusammenführen von Streams in Java

Streams in Java zusammenführen

1. Überblick

In diesem kurzen Artikel erklären wir verschiedene Möglichkeiten zum Zusammenführen von JavaStreams - was keine sehr intuitive Operation ist.

2. Verwenden von Plain Java

Die JDK 8Stream-Klasse verfügt über einige nützliche statische Dienstprogrammmethoden. Schauen wir uns dieconcat()-Methode genauer an.

2.1. Zusammenführen von zweiStreams

Der einfachste Weg, 2Streams zu kombinieren, ist die Verwendung der statischenStream.concat()-Methode:

@Test
public void whenMergingStreams_thenResultStreamContainsElementsFromBoth() {
    Stream stream1 = Stream.of(1, 3, 5);
    Stream stream2 = Stream.of(2, 4, 6);

    Stream resultingStream = Stream.concat(stream1, stream2);

    assertEquals(
      Arrays.asList(1, 3, 5, 2, 4, 6),
      resultingStream.collect(Collectors.toList()));
}

2.2. Zusammenführen mehrererStreams

Wenn wir mehr als 2Streams,zusammenführen müssen, werden die Dinge etwas komplexer. Eine Möglichkeit besteht darin, die ersten beiden Streams zu verketten und dann das Ergebnis mit dem nächsten zu verketten und so weiter.

Das nächste Codefragment zeigt dies in Aktion:

@Test
public void given3Streams_whenMerged_thenResultStreamContainsAllElements() {
    Stream stream1 = Stream.of(1, 3, 5);
    Stream stream2 = Stream.of(2, 4, 6);
    Stream stream3 = Stream.of(18, 15, 36);

    Stream resultingStream = Stream.concat(
      Stream.concat(stream1, stream2), stream3);

    assertEquals(
      Arrays.asList(1, 3, 5, 2, 4, 6, 18, 15, 36),
      resultingStream.collect(Collectors.toList()));
}

Wie wir sehen können, wird dieser Ansatz für mehr Streams nicht durchführbar. Natürlich können wir Zwischenvariablen oder Hilfsmethoden erstellen, um die Lesbarkeit zu verbessern, aber hier ist eine bessere Option:

@Test
public void given4Streams_whenMerged_thenResultStreamContainsAllElements() {
    Stream stream1 = Stream.of(1, 3, 5);
    Stream stream2 = Stream.of(2, 4, 6);
    Stream stream3 = Stream.of(18, 15, 36);
    Stream stream4 = Stream.of(99);

    Stream resultingStream = Stream.of(
      stream1, stream2, stream3, stream4)
      .flatMap(i -> i);

    assertEquals(
      Arrays.asList(1, 3, 5, 2, 4, 6, 18, 15, 36, 99),
      resultingStream.collect(Collectors.toList()));
}

Was hier passiert ist:

  • Wir erstellen zuerst ein neuesStream, das die 4Streams, enthält, was zu einemStream<Stream<Integer>> führt

  • Dann setzen wir dies mit der Identitätsfunktion inStream<Integer> um

3. Verwenden von StreamEx

StreamEx ist eine Open-Source-Java-Bibliothek, die die Möglichkeiten von Java 8-Streams erweitert. Es verwendet die KlasseStreamExals Erweiterung derStream-Schnittstelle des JDK.

3.1. Zusammenführen vonStreams

Mit der StreamEx-Bibliothek können wir Streams mithilfe der Instanzmethodeappend()zusammenführen:

@Test
public void given4Streams_whenMerged_thenResultStreamContainsAllElements() {
    Stream stream1 = Stream.of(1, 3, 5);
    Stream stream2 = Stream.of(2, 4, 6);
    Stream stream3 = Stream.of(18, 15, 36);
    Stream stream4 = Stream.of(99);

    Stream resultingStream = StreamEx.of(stream1)
      .append(stream2)
      .append(stream3)
      .append(stream4);

    assertEquals(
      Arrays.asList(1, 3, 5, 2, 4, 6, 18, 15, 36, 99),
      resultingStream.collect(Collectors.toList()));
}

Da es sich um eine Instanzmethode handelt, können wir sie einfach verketten und mehrere Streams anhängen.

Beachten Sie, dass wir mittoList() auchList aus dem Stream erstellen können, wenn wir die VariableresultingStream in den TypStreamEx eingeben.

3.2. Zusammenführen von Streams mitprepend()

StreamEx enthält auch eine Methode, die Elemente voreinander hinzufügt undprepend() heißt:

@Test
public void given3Streams_whenPrepended_thenResultStreamContainsAllElements() {
    Stream stream1 = Stream.of("foo", "bar");
    Stream openingBracketStream = Stream.of("[");
    Stream closingBracketStream = Stream.of("]");

    Stream resultingStream = StreamEx.of(stream1)
      .append(closingBracketStream)
      .prepend(openingBracketStream);

    assertEquals(
      Arrays.asList("[", "foo", "bar", "]"),
      resultingStream.collect(Collectors.toList()));
}

4. Mit Jooλ

jOOλ ist eine JDK 8-kompatible Bibliothek, die nützliche Erweiterungen für das JDK bietet. Die wichtigste Stream-Abstraktion heißt hierSeq. Beachten Sie, dass dies ein sequentieller und geordneter Stream ist, sodass das Aufrufen vonparallel() keine Auswirkung hat.

4.1. Streams zusammenführen

Genau wie die StreamEx-Bibliothek verfügt jOOλ über eineappend()-Methode:

@Test
public void given2Streams_whenMerged_thenResultStreamContainsAllElements() {
    Stream seq1 = Stream.of(1, 3, 5);
    Stream seq2 = Stream.of(2, 4, 6);

    Stream resultingSeq = Seq.ofType(seq1, Integer.class)
      .append(seq2);

    assertEquals(
      Arrays.asList(1, 3, 5, 2, 4, 6),
      resultingSeq.collect(Collectors.toList()));
}

Es gibt auch eine bequeme MethodetoList(), wenn wir die VariableresultingSeqin den Typ jOOλSeqeingeben.

4.2. Streams mitprepend() zusammenführen

Da eineappend()-Methode existiert, gibt es erwartungsgemäß auch eineprepend()-Methode in jOOλ:

@Test
public void given3Streams_whenPrepending_thenResultStreamContainsAllElements() {
    Stream seq = Stream.of("foo", "bar");
    Stream openingBracketSeq = Stream.of("[");
    Stream closingBracketSeq = Stream.of("]");

    Stream resultingStream = Seq.ofType(seq, String.class)
      .append(closingBracketSeq)
      .prepend(openingBracketSeq);

    Assert.assertEquals(
      Arrays.asList("[", "foo", "bar", "]"),
      resultingStream.collect(Collectors.toList()));
}

5. Fazit

Wir haben gesehen, dass das Zusammenführen von Streams mit JDK 8 relativ einfach ist. Wenn wir viel zusammenführen müssen, kann es aus Gründen der Lesbarkeit hilfreich sein, die StreamEx- oder JOOλ-Bibliothek zu verwenden.

Sie finden den Quellcodeover on GitHub.