1. 概要

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

2. プレーンJavaの使用

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

2.1. 2つのストリームのマージ

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

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

    Stream<Integer> resultingStream = Stream.concat(stream1, stream2);

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

2.2. 複数のストリームのマージ

2つ以上のストリームをマージする必要がある場合、はもう少し複雑になります。 1つの可能性は、最初の2つのストリームを連結し、次に結果を次のストリームと連結することです。

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

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

    Stream<Integer> 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<Integer> stream1 = Stream.of(1, 3, 5);
    Stream<Integer> stream2 = Stream.of(2, 4, 6);
    Stream<Integer> stream3 = Stream.of(18, 15, 36);
    Stream<Integer> stream4 = Stream.of(99);

    Stream<Integer> 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を含むストリーム、 その結果、 ストリーム >>
  • 次に、 flatMap() これをストリーム恒等関数を使用する

3. StreamExの使用

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

3.1. ストリームのマージ

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

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

    Stream<Integer> 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には、 prepare()と呼ばれる要素を相互に追加するメソッドも含まれています。

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

    Stream<String> 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<Integer> seq1 = Stream.of(1, 3, 5);
    Stream<Integer> seq2 = Stream.of(2, 4, 6);

    Stream<Integer> 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λには prepare()メソッドもあります。

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

    Stream<String> 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λライブラリを使用すると便利な場合があります。

ソースコードはGitHubにあります。