1. 概要

このチュートリアルでは、複数のコレクションを1つの論理コレクションに連結する方法を説明します。

5つの異なるアプローチを検討します。2つはJava8を使用し、1つはGuavaを使用し、1つはApache Commons Collectionsを使用し、もう1つは標準のJava7SDKのみを使用します。

次の例では、次のコレクションについて考えてみましょう。

Collection<String> collectionA = Arrays.asList("S", "T");
Collection<String> collectionB = Arrays.asList("U", "V");

2. Java 8 StreamAPIの使用

JavaAPIのStreamインターフェースは、コレクションの処理を容易にする便利なメソッドを提供します。 コレクションの結合に使用される2つのメソッド[concat() flatMap()]を見てみましょう。

Stream を取得すると、それに対して集約操作を実行できます。

2.1. concat()メソッドの使用

静的メソッドconcat()は、要素が最初の Stream のすべての要素である、遅延連結された Stream を作成することにより、2つのStreamsを論理的に結合します。 2番目のStreamのすべての要素が続きます。

以下の例では、 concat()メソッドを使用して、collectionAcollectionBを組み合わせてみましょう。

Stream<String> combinedStream = Stream.concat(
  collectionA.stream(),
  collectionB.stream());

3つ以上のStreamsを組み合わせる必要がある場合は、元の呼び出し内から concat()メソッドを再度呼び出すことができます。

Stream<String> combinedStream = Stream.concat(
  Stream.concat(collectionA.stream(), collectionB.stream()), 
  collectionC.stream());

Java 8 Streams は再利用できないため、変数に割り当てる際にはこれを考慮に入れる必要があることに注意してください。

2.2. flatMap()メソッドを使用する

flatMap()メソッドは、この Stream の各要素を、によって生成されたマップされた Stream のコンテンツに置き換えた後、Streamを返します。提供されたマッピング関数を各要素に適用します。

以下の例は、 flatMap()メソッドを使用したコレクションのマージを示しています。 最初に、要素が2つのコレクションである Stream を取得し、次に Stream をフラット化してから、マージされたリストに収集します。

Stream<String> combinedStream = Stream.of(collectionA, collectionB)
  .flatMap(Collection::stream);
Collection<String> collectionCombined = 
  combinedStream.collect(Collectors.toList());

3. グアバの使用

GoogleのGuavaライブラリは、コレクションを操作するためのいくつかの便利なメソッドを提供し、Java6以降で使用できます。

3.1. Iterables.concat()メソッドの使用

Iterables.concat()メソッドは、コレクションのマージに使用されるGuavaの便利なメソッドの1つです。

Iterable<String> combinedIterables = Iterables.unmodifiableIterable(
  Iterables.concat(collectionA, collectionA));

返されるIterableは、コレクションに変換できます。

Collection<String> collectionCombined = Lists.newArrayList(combinedIterables);

3.2. Mavenの依存関係

次の依存関係をMavenpom.xml ファイルに追加して、プロジェクトにGuavaライブラリを含めます。

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

Guavaライブラリの最新バージョンは、 MavenCentralリポジトリにあります。

4. ApacheCommonsCollectionsの使用

Apache Commons Collectionsは、さまざまなコレクションの操作を支援するユーティリティのさらに別のライブラリです。 ライブラリは、コレクションを組み合わせるために使用できる2つのユーティリティメソッドを提供します。 このセクションでは、これらのメソッドがどのように機能するかを理解しましょう。

4.1. IterableUtils.chainedIterable()メソッドの使用

IterableUtils クラスは、Iterableインスタンスのユーティリティメソッドとデコレータを提供します。 chainedIterable()メソッドを提供します。このメソッドを使用して、複数のIterableを1つに結合できます。

Iterable<String> combinedIterables = IterableUtils.chainedIterable(
  collectionA, collectionB);

4.2. CollectionUtils.union()メソッドの使用

Collection インスタンスのユーティリティメソッドとデコレータは、CollectionUtilsクラスによって提供されます。 このクラスのunion()メソッドは、指定されたIterableインスタンスの結合を含むCollectionを返します。

Iterable<String> combinedIterables = CollectionUtils.union(
  collectionA, collectionB);

union()メソッドの場合、返されるコレクション内の各要素のカーディナリティは、指定された2つのIterables内のその要素のカーディナリティの最大値に等しくなります。 つまり、結合されたコレクションは、最初のコレクションの要素と、最初のコレクションには存在しなかった2番目のコレクションの要素のみで構成されます。

4.3. Mavenの依存関係

次の依存関係をMavenpom.xml ファイルに追加して、プロジェクトにApacheCommonsCollectionsライブラリを含めます。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>

Apache Commonsライブラリの最新バージョンは、 MavenCentralリポジトリにあります。

5. Java7の使用

まだJava7を使用していて、Guavaなどのサードパーティライブラリを避けたい場合は、 addAll()メソッドを使用して複数のコレクションの要素を結合するか、独自のユーティリティメソッドを記述して[ X226X]Iterables。

5.1. addAll()メソッドの使用

もちろん、コレクションを結合するための最も簡単な解決策は、次の List の例のように、 addAll()メソッドを使用することですが、このメソッドは追加の参照を含む新しいコレクションを作成することに注意してください。最初の2つのコレクションにある同じオブジェクトに:

List<String> listC = new ArrayList<>();
listC.addAll(listA);
listC.addAll(listB);

5.2. カスタムconcat()メソッドの記述

次の例では、2つの Iterables を受け入れ、マージされた Iterableオブジェクトを返すconcat()メソッドを定義します。

public static <E> Iterable<E> concat(
  Iterable<? extends E> i1,
  Iterable<? extends E> i2) {
        return new Iterable<E>() {
            public Iterator<E> iterator() {
                return new Iterator<E>() {
                    Iterator<? extends E> listIterator = i1.iterator();
                    Boolean checkedHasNext;
                    E nextValue;
                    private boolean startTheSecond;

                    void theNext() {
                        if (listIterator.hasNext()) {
                            checkedHasNext = true;
                            nextValue = listIterator.next();
                        } else if (startTheSecond)
                            checkedHasNext = false;
                        else {
                            startTheSecond = true;
                            listIterator = i2.iterator();
                            theNext();
                        }
                    }

                    public boolean hasNext() {
                        if (checkedHasNext == null)
                            theNext();
                        return checkedHasNext;
                    }

                    public E next() {
                        if (!hasNext())
                            throw new NoSuchElementException();
                        checkedHasNext = null;
                        return nextValue;
                    }

                    public void remove() {
                        listIterator.remove();
                    }
                };
            }
        };
    }

concat()メソッドは、2つのコレクションを引数として渡すことで呼び出すことができます。

Iterable<String> combinedIterables = concat(collectionA, collectionB);
Collection<String> collectionCombined = makeListFromIterable(combinedIterables);

IterableListとして使用できるようにする必要がある場合は、 makeListFromIterable()メソッドを使用してListを作成することもできます。 Iterable のメンバー:

public static <E> List<E> makeListFromIterable(Iterable<E> iter) {
    List<E> list = new ArrayList<E>();
    for (E item : iter) {
        list.add(item);
    }
    return list;
}

6. 結論

この記事では、Javaで2つのコレクションを論理的に組み合わせるために、それらに含まれるオブジェクトへの追加の参照を作成せずに、いくつかの異なる方法について説明しました。

このチュートリアルのコードは、Githubから入手できます。