1. 概要

この記事では、JavaコレクションフレームワークのArrayListクラスを見ていきます。 その特性、一般的な使用例、およびその長所と短所について説明します。

ArrayList はJavaコアライブラリ内にあるため、追加のライブラリは必要ありません。 これを使用するには、次のインポートステートメントを追加するだけです。

import java.util.ArrayList;

List は、ある値が複数回発生する可能性がある、順序付けられた値のシーケンスを表します。

ArrayList は、配列の上に構築された List 実装の1つであり、要素を追加/削除すると動的に拡大および縮小できます。 要素は、ゼロから始まるインデックスによって簡単にアクセスできます。 この実装には、次のプロパティがあります。

  • ランダムアクセスにはO(1)の時間がかかります
  • 要素の追加には、償却定数時間がかかります O(1)
  • 挿入/削除にはO(n)の時間がかかります
  • 検索には、ソートされていない配列の場合は O(n)時間、ソートされた配列の場合は O(log n)時間がかかります。

2. ArrayListを作成します

ArrayList にはいくつかのコンストラクターがあり、このセクションではそれらすべてを紹介します。

まず、 ArrayList は汎用クラスであるため、任意の型でパラメーター化でき、コンパイラーは、たとえば、Integerを配置できないようにします。 Stringsのコレクション内の値。 また、コレクションから要素を取得するときに要素をキャストする必要はありません。

次に、汎用インターフェイス List を変数タイプとして使用することをお勧めします。これは、特定の実装から分離するためです。

2.1. デフォルトの引数なしコンストラクタ

List<String> list = new ArrayList<>();
assertTrue(list.isEmpty());

空のArrayListインスタンスを作成しているだけです。

2.2. 初期容量を受け入れるコンストラクター

List<String> list = new ArrayList<>(20);

ここでは、基になる配列の初期の長さを指定します。 これにより、新しいアイテムを追加するときに不要なサイズ変更を回避できる場合があります。

2.3. コレクションを受け入れるコンストラクター

Collection<Integer> numbers 
  = IntStream.range(0, 10).boxed().collect(toSet());

List<Integer> list = new ArrayList<>(numbers);
assertEquals(10, list.size());
assertTrue(numbers.containsAll(list));

Collection インスタンスの要素は、基になる配列にデータを設定するために使用されることに注意してください。

3. ArrayListに要素を追加します

要素は、最後または特定の位置に挿入できます。

List<Long> list = new ArrayList<>();

list.add(1L);
list.add(2L);
list.add(1, 3L);

assertThat(Arrays.asList(1L, 3L, 2L), equalTo(list));

コレクションまたは複数の要素を一度に挿入することもできます。

List<Long> list = new ArrayList<>(Arrays.asList(1L, 2L, 3L));
LongStream.range(4, 10).boxed()
  .collect(collectingAndThen(toCollection(ArrayList::new), ys -> list.addAll(0, ys)));
assertThat(Arrays.asList(4L, 5L, 6L, 7L, 8L, 9L, 1L, 2L, 3L), equalTo(list));

4. ArrayListを反復処理します

使用可能なイテレータには、IteratorListIteratorの2種類があります。

前者はリストを一方向にトラバースする機会を与えますが、後者はリストを両方向にトラバースすることを可能にします。

ここでは、ListIteratorのみを表示します。

List<Integer> list = new ArrayList<>(
  IntStream.range(0, 10).boxed().collect(toCollection(ArrayList::new))
);
ListIterator<Integer> it = list.listIterator(list.size());
List<Integer> result = new ArrayList<>(list.size());
while (it.hasPrevious()) {
    result.add(it.previous());
}

Collections.reverse(list);
assertThat(result, equalTo(list));

イテレータを使用して要素を検索、追加、または削除することもできます。

5. ArrayListを検索します

コレクションを使用して検索がどのように機能するかを示します。

List<String> list = LongStream.range(0, 16)
  .boxed()
  .map(Long::toHexString)
  .collect(toCollection(ArrayList::new));
List<String> stringsToSearch = new ArrayList<>(list);
stringsToSearch.addAll(list);

5.1. ソートされていないリストの検索

要素を見つけるには、 indexOf()または lastIndexOf()メソッドを使用できます。 どちらもオブジェクトを受け入れ、int値を返します。

assertEquals(10, stringsToSearch.indexOf("a"));
assertEquals(26, stringsToSearch.lastIndexOf("a"));

述語を満たすすべての要素を検索する場合は、次のように述語を使用してJava 8 Stream API (詳細はこちら)を使用してコレクションをフィルタリングできます。

Set<String> matchingStrings = new HashSet<>(Arrays.asList("a", "c", "9"));

List<String> result = stringsToSearch
  .stream()
  .filter(matchingStrings::contains)
  .collect(toCollection(ArrayList::new));

assertEquals(6, result.size());

forループまたはイテレータを使用することもできます。

Iterator<String> it = stringsToSearch.iterator();
Set<String> matchingStrings = new HashSet<>(Arrays.asList("a", "c", "9"));

List<String> result = new ArrayList<>();
while (it.hasNext()) {
    String s = it.next();
    if (matchingStrings.contains(s)) {
        result.add(s);
    }
}

5.2. ソートされたリストの検索

ソートされた配列がある場合は、線形検索よりも高速に機能するバイナリ検索アルゴリズムを使用できます。

List<String> copy = new ArrayList<>(stringsToSearch);
Collections.sort(copy);
int index = Collections.binarySearch(copy, "f");
assertThat(index, not(equalTo(-1)));

要素が見つからない場合は、-1が返されることに注意してください。

6. ArrayListから要素を削除します

要素を削除するには、そのインデックスを見つけてから、 remove()メソッドを使用して削除を実行する必要があります。 このメソッドのオーバーロードされたバージョンは、オブジェクトを受け入れ、それを検索し、等しい要素の最初の出現の削除を実行します。

List<Integer> list = new ArrayList<>(
  IntStream.range(0, 10).boxed().collect(toCollection(ArrayList::new))
);
Collections.reverse(list);

list.remove(0);
assertThat(list.get(0), equalTo(8));

list.remove(Integer.valueOf(0));
assertFalse(list.contains(0));

ただし、Integerなどのボックス型を操作する場合は注意が必要です。 特定の要素を削除するには、最初に int 値をボックス化する必要があります。そうしないと、要素はそのインデックスによって削除されます。

前述のStreamAPI を使用していくつかのアイテムを削除することもできますが、ここでは示しません。 この目的のために、イテレータを使用します。

Set<String> matchingStrings
 = HashSet<>(Arrays.asList("a", "b", "c", "d", "e", "f"));

Iterator<String> it = stringsToSearch.iterator();
while (it.hasNext()) {
    if (matchingStrings.contains(it.next())) {
        it.remove();
    }
}

7. 概要

この簡単な記事では、JavaのArrayListについて説明しました。

ArrayList インスタンスを作成する方法、さまざまなアプローチを使用して要素を追加、検索、または削除する方法を示しました。

いつものように、すべてのコードサンプルはGitHubにあります。