List と ArrayList をざっくりイメージする
まずイメージからいきます。
配列 int[] は「長さが固定の箱の列」でした。
一方で List / ArrayList は「あとから増やしたり減らしたりできる箱の列」です。
List は「こういう振る舞いをする“列”の抽象的な型(インターフェース)」、
ArrayList は「List の具体的な実装クラス(中身は配列ベース)」だと思ってください。
コードで書くと、よく見るのはこういう形です。
List<String> list = new ArrayList<>();
Java左側の List は「どんな振る舞いをするか」の約束。
右側の new ArrayList<>() が「実際の中身(配列を使っているクラス)」です。
「基本的には List で変数を宣言しておき、中身として ArrayList を new する」
この形が Java では“お作法”に近いです。
配列と List / ArrayList の違いを最初にハッキリさせる
長さが固定か、増減できるか
配列は一度作ったら長さを変えられません。
int[] a = new int[3]; // 長さ 3 で固定
// あとから「長さ 4 にしたい」はできない
JavaArrayList は、要素を add するたびに内部でうまく拡張してくれます。
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
list.add(30);
// いくらでも add していける(メモリが許す限り)
Java「あとから数が増える可能性があるデータ」は、基本的に List / ArrayList で持つと思ってください。
型の書き方(プリミティブは直接入らない)
配列なら、int[] や double[] のようにプリミティブ型を直接使えます。
int[] a = new int[3];
Javaしかし List は「オブジェクトのコレクション」なので、プリミティブはそのまま入れられません。
代わりにラッパークラス(Integer, Double など)を使います。
List<Integer> list = new ArrayList<>();
list.add(10); // オートボクシングされて Integer になる
JavaList<int> とは書けない、ここを一度ちゃんと意識しておくと混乱が減ります。
ArrayList の基本操作(add / get / size / remove)
要素を追加する add
ArrayList に要素を入れるのは add です。
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Carol");
System.out.println(names); // [Alice, Bob, Carol]
Javaこのとき、サイズ(要素数)は 3 です。
あとからいくらでも add できます。配列のように「最初に長さを決める」必要はありません。
要素数を調べる size
要素が何個入っているかは size() で分かります。
System.out.println(names.size()); // 3
Java配列の length とよく似ていますが、
配列はフィールド(arr.length)、List はメソッド(list.size())です。
要素を取り出す get(インデックスは 0 から)
n 番目の要素を取り出すのは get(index) です。
インデックスは配列と同じく 0 から始まります。
String first = names.get(0); // "Alice"
String second = names.get(1); // "Bob"
Java存在しないインデックス(たとえば 3 以上)を指定すると IndexOutOfBoundsException になります。
ここは配列と同じ感覚です。
要素を削除する remove
remove は大きく二通りあります。
インデックスで削除:
names.remove(1); // index 1 の "Bob" を削除
System.out.println(names); // [Alice, Carol]
Java値で削除:
names.remove("Alice"); // "Alice" に等しい要素を削除
System.out.println(names); // [Carol]
Javaremove(1) は「インデックス 1 を削除」remove("1") は「文字列 “1” を削除」
というように、引数の型によって意味が変わるので、ここはよく注意してください。
List を for 文や拡張 for で回す
古典的な for 文で回す
配列と同じように、インデックスで回すパターンです。
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
System.out.println(i + ": " + name);
}
Javasize() は毎回呼んでも問題ないですが、性能を気にするなら事前に変数に入れることもあります。
int n = names.size();
for (int i = 0; i < n; i++) {
...
}
Java拡張 for 文(for-each)でシンプルに回す
インデックスが特に要らないなら、「拡張 for(for-each)」のほうが読みやすくなります。
for (String name : names) {
System.out.println(name);
}
Javafor (要素の型 変数名 : コレクション) という形です。
中身を順番に全部見るだけなら、この書き方を積極的に使うとコードがきれいになります。
List と ArrayList の関係(インターフェースと実装)
なぜ変数は List 型で持つのか
よくこう書きます。
List<String> names = new ArrayList<>();
Java「最初から ArrayList で宣言してもよくない?」と思うかもしれません。
ArrayList<String> names = new ArrayList<>();
Javaこれでも動きます。ただし、設計としては最初の書き方が好まれます。
理由は、「あとから中身の実装を差し替えやすいから」です。
List というのは、「順番があって、重複を許すコレクション」というインターフェース(振る舞いの約束)です。
ArrayList は、その List を配列ベースで実装したクラスです。
将来、「この List は LinkedList にしたほうが都合が良くなった」となったとき、
変数の型を List にしておけば、右側だけ変えれば差し替えられます。
List<String> names = new LinkedList<>();
Java「左側は List、右側は具体クラス」という形を癖づけておくと、
設計として柔軟になります(そして現場の Java コードのほとんどがそう書いています)。
よくあるハマりポイントと注意点
new し忘れて NullPointerException
これ、初心者がほぼ全員一度はやらかします。
List<String> names; // 宣言だけ
names.add("Alice"); // NullPointerException
Java変数を宣言しただけだと、中身は null のままです。
必ず new ArrayList<>() してから使います。
List<String> names = new ArrayList<>();
names.add("Alice"); // OK
Javaフィールドでも同じです。コンストラクタなどで必ず初期化しましょう。
型パラメータ(<String>)を書き忘れる
List はジェネリクスを使うので、<> の中の型を省略すると「生の型(raw type)」になり、
コンパイラから警告されたり、キャストが必要になったりします。
List list = new ArrayList(); // 推奨されない書き方
list.add("abc");
String s = (String) list.get(0); // キャストが必要
Java正しくはこうです。
List<String> list = new ArrayList<>();
list.add("abc");
String s = list.get(0); // キャスト不要、型安全
Javaジェネリクスをちゃんと書くと、コンパイル時に型チェックしてくれるので、
バグが減ります。ここは少し面倒でも、きちんと書いたほうが長期的に得です。
まとめ:List / ArrayList を頭の中でこう整理しておく
最後に、初心者向けに List / ArrayList のイメージをまとめます。
配列は「長さ固定」。List / ArrayList は「あとから増やしたり減らしたりできる列」。
List は「インターフェース(こう振る舞うべきという約束)」、ArrayList は「配列ベースの具体実装」。
宣言は List<型> 変数 = new ArrayList<>(); という形が基本。
要素追加は add、参照は get、要素数は size、削除は remove。
for 文・拡張 for 文で自然に回して使う。
