JavaでコレクションをArrayListに変換する
1. 概要
Javaコレクションをあるタイプから別のタイプに変換することは、一般的なプログラミングタスクです。 このチュートリアルでは、任意のタイプのコレクションをArrayListに変換します。
チュートリアル全体を通して、Fooオブジェクトのコレクションがすでにあると想定します。 そこから、さまざまなアプローチを使用してArrayListを作成します。
2. 例の定義
ただし、続行する前に、入力と出力をモデル化しましょう。
ソースは任意のタイプのコレクションである可能性があるため、Collectionインターフェイスを使用して宣言します。
Collection<Foo> srcCollection;
同じ要素タイプでArrayListを生成する必要があります。
ArrayList<Foo> newList;
3. ArrayListコンストラクターの使用
コレクションを新しいコレクションにコピーする最も簡単な方法は、そのコンストラクターを使用することです。
以前のArrayListガイドでは、ArrayListコンストラクターがコレクションパラメーターを受け入れることができることを学びました。
ArrayList<Foo> newList = new ArrayList<>(srcCollection);
- 新しいArrayListには、ソースコレクションのFoo要素の浅いコピーが含まれています。
- 順序は、ソースコレクションの順序と同じです。
コンストラクターは単純であるため、ほとんどのシナリオで優れたオプションになります。
4. StreamsAPIの使用
ここで、 Streams APIを利用して、既存のコレクションからArrayListを作成しましょう:
ArrayList<Foo> newList = srcCollection.stream().collect(toCollection(ArrayList::new));
このスニペットでは:
- ソースコレクションからストリームを取得し、 collect()演算子を適用して、リストを作成します。
- ArrayList :: new を指定して、必要なリストタイプを取得します
- このコードは、浅いコピーも生成します。
正確なListタイプを気にしない場合は、次のように簡略化できます。
List<Foo> newList = srcCollection.stream().collect(toList());
toCollection()および toList()は、Collectorsから静的にインポートされることに注意してください。 詳細については、Java8のコレクターに関するガイドを参照してください。
5. ディープコピー
「浅いコピー」について言及する前に。 つまり、新しいリストの要素は、ソースコレクションにまだ存在するとまったく同じFooインスタンスであるということです。 そのため、参照によりFooをnewListにコピーしました。
いずれかのコレクションのFooインスタンスの内容を変更すると、の変更は両方のコレクションに反映されます。 したがって、一方のコレクションの要素を、もう一方のコレクションを変更せずに変更する場合は、「ディープコピー」を実行する必要があります。
Foo をディープコピーするために、各要素に対して完全に新しいFooインスタンスを作成します。 したがって、すべてのFooフィールドを新しいインスタンスにコピーする必要があります。
Foo クラスを定義して、それ自体をディープコピーする方法を認識できるようにします。
public class Foo {
private int id;
private String name;
private Foo parent;
public Foo(int id, String name, Foo parent) {
this.id = id;
this.name = name;
this.parent = parent;
}
public Foo deepCopy() {
return new Foo(
this.id, this.name, this.parent != null ? this.parent.deepCopy() : null);
}
}
ここでは、フィールドidとnameがintとStringであることがわかります。 これらのデータ型は値によってコピーされます。 したがって、両方を簡単に割り当てることができます。
parent フィールドは、クラスである別のFooです。 Foo が変更された場合、その参照を共有するコードはすべて、これらの変更の影響を受けます。 親フィールドをディープコピーする必要があります。
これで、ArrayList変換に戻ることができます。 ディープコピーをフローに挿入するには、マップ演算子が必要です。
ArrayList<Foo> newList = srcCollection.stream()
.map(foo -> foo.deepCopy())
.collect(toCollection(ArrayList::new));
どちらかのコレクションの内容を、もう一方に影響を与えることなく変更できます。
ディープコピーは、要素の数とデータの深さによっては、時間のかかるプロセスになる可能性があります。 ここで並列ストリームを使用すると、必要に応じてパフォーマンスが向上する場合があります。
6. リストの順序を制御する
デフォルトでは、ストリームは、ソースコレクションで検出されたのと同じ順序で要素をArrayListに配信します。
その順序を変更したい場合、sorted()演算子をストリームに適用できます。 Foo オブジェクトを名前で並べ替えるには:
ArrayList<Foo> newList = srcCollection.stream()
.sorted(Comparator.comparing(Foo::getName))
.collect(toCollection(ArrayList::new));
ストリームの順序付けの詳細については、この以前のチュートリアルを参照してください。
7. 結論
ArrayList コンストラクターは、Collectionのコンテンツを新しいArrayListに取り込む効果的な方法です。
ただし、結果のリストを微調整する必要がある場合は、StreamsAPIがプロセスを変更するための強力な方法を提供します。
この記事で使用されているコードは、GitHubで全体を見つけることができます。