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