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

1概要

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

2プレーンJava の使い方

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

2.1. 2つの Streams を結合する

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

2つ以上の Streamをマージする必要があるとき、 物事はもう少し複雑になります。 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つの Streamsを含む新しい Stream__を作成します。

Stream <Stream <Integer>> になります。 ** それから、 flatMap() アイデンティティーを使用して Stream <Integer> にこれを__します。

関数

3 StreamEx を使用する

StreamEx は、Java 8 Streamsの可能性を広げるオープンソースのJavaライブラリです。 JDKの Stream インタフェースの拡張として、 StreamEx クラスが使用されています。

3.1. __Stream __s をマージする

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には、 prepend() という名前の要素を順番に追加するメソッドも含まれています。

@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に便利な拡張機能を提供するJDK 8互換のライブラリです。ここで最も重要なストリームの抽象化は 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λには prepend() メソッドもあります。

@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で利用可能 のソースコードを見つけることができます。

前の投稿:JMXの基本的な紹介
次の投稿:Java Weekly、Issue 211