Javaでストリームをマージする

Javaでのストリームのマージ

1. 概要

この簡単な記事では、JavaStreamsをマージするさまざまな方法について説明します。これはあまり直感的な操作ではありません。

2. プレーンJavaの使用

JDK 8Streamクラスには、いくつかの便利な静的ユーティリティメソッドがあります。 concat()メソッドを詳しく見てみましょう。

2.1. 2つのStreamsをマージする

2Streamsを組み合わせる最も簡単な方法は、静的なStream.concat()メソッドを使用することです。

@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. 複数のStreamsをマージする

2Streams,を超えてマージする必要がある場合、状況は少し複雑になります。 1つの可能性は、最初の2つのストリームを連結してから、次のストリームと結果を連結することです。

次のコードスニペットは、これを実際に示しています。

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

ご覧のとおり、このアプローチはより多くのストリームに対して実行不可能になります。 もちろん、中間変数またはヘルパーメソッドを作成して読みやすくすることもできますが、ここではより良いオプションを示します。

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

ここで何が起こるかです:

  • 最初に、4つのStreams,を含む新しいStreamを作成します。これにより、Stream<Stream<Integer>>が生成されます。

  • 次に、恒等関数を使用して、これをStream<Integer>flatMap()します。

3. StreamExの使用

StreamExは、Java8ストリームの可能性を拡張するオープンソースのJavaライブラリです。 JDKのStreamインターフェースの拡張機能としてStreamExクラスを使用します。

3.1. Streamsのマージ

StreamExライブラリを使用すると、append()インスタンスメソッドを使用してストリームをマージできます。

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

これはインスタンスメソッドであるため、簡単にチェーン化して複数のストリームを追加できます。

resultingStream変数をStreamExタイプに入力すると、toList()を使用してストリームからListを作成することもできることに注意してください。

3.2. prepend()を使用したスト​​リームのマージ

StreamExには、prepend()と呼ばれる要素を相互に追加するメソッドも含まれています。

@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. Jooλの使用

jOOλは、JDKに便利な拡張機能を提供するJDK8互換ライブラリです。 ここで最も重要なストリームの抽象化はSeqと呼ばれます。 これはシーケンシャルで順序付けられたストリームであるため、parallel()を呼び出しても効果がないことに注意してください。

4.1. ストリームのマージ

StreamExライブラリと同様に、jOOλにはappend()メソッドがあります。

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

また、resultingSeq変数をjOOλSeq型に入力すると、便利なtoList()メソッドがあります。

4.2. ストリームとprepend()のマージ

予想どおり、append()メソッドが存在するため、jOOλにはprepend()メソッドもあります。

@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. 結論

JDK 8を使用すると、ストリームのマージが比較的簡単であることがわかりました。 多くのマージを行う必要がある場合、読みやすくするためにStreamExまたはjOOλライブラリを使用すると有益な場合があります。

ソースコードover on GitHubを見つけることができます。