Java ArrayListガイド

1概要

この記事では、Java Collections Frameworkの ArrayList クラスを見ていきます。その特性、一般的な使用例、およびその長所と短所について説明します。

ArrayList はJava Core Librariesの中にあるので、追加のライブラリは必要ありません。それを使用するためには、単に次のimport文を追加してください。

import java.util.ArrayList;

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

ArrayList は、配列の上に構築された List 実装の1つで、要素を追加または削除すると動的に拡大および縮小できます。

要素は、ゼロから始まるインデックスによって簡単にアクセスできます。

この実装は以下のプロパティを持ちます。

  • ランダムアクセスは O(1) 時間がかかります

  • 要素を追加することは償却された一定時間かかります

  • 挿入/削除には O(n) 時間がかかります

  • 検索にはソートされていない配列では O(n) 時間がかかり、

ソートされたもの

2作成

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

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

次に、ジェネリックインターフェイス List を変数型として使用することをお勧めします。これは、特定の実装から切り離すためです。

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

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

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

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

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

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

2.3. Collection を受け付けるコンストラクタ

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

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

Collection インスタンスの要素は、基礎となる配列を生成するために使用されています。

3要素を追加する

要素は末尾または特定の位置に挿入できます。

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リストを繰り返す+

**

使用できるイテレータには、 Iterator ListIterator の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リスト内を検索する

**

コレクションを使用した検索のしくみを説明します。

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"));

述語を満たすすべての要素を見つけたい場合は、次のように Predicate を使用して、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. 要素を削除する

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

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 valueをボックス化する必要があります。そうしないと、要素はインデックスによって削除されます。

前述の Stream API を使用して複数のアイテムを削除することもできますが、ここでは紹介しません。このためにイテレータを使います。

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 インスタンスを作成する方法、さまざまな方法で要素を追加、検索、削除する方法を示しました。

いつものように、あなたはhttps://github.com/eugenp/tutorials/tree/master/core-java-collections[GitHub]ですべてのコードサンプルを見つけることができます。