List作成構文
基本的な構文は以下の通りです。
Listの中には、ArrayListやLinkedListという型が存在しますが、
今回は扱いやすいArrayListの解説になります。
List<型> list = new ArrayList<>();
型推論(var)を使って記述する場合は、以下の通りです。
var list = new ArrayList<型>();
型はラッパークラスを指定してください。
例えばint型のラッパークラスはIntegerになります。
基本(プリミティブ)型 | ラッパークラス | 備考 |
byte | Byte | |
short | Short | |
int | Integer | よく使います |
double | Double | よく使います |
long | Long | |
float | Float | |
boolean | Boolean | よく使います |
char | Char |
ちなみに、文字列を格納するString型は参照型ですので、Listに入れることが可能です。
データ型の最初の1文字目が大文字のものは格納できます。
ですので、クラスもListに格納することが可能です。
使用頻度が高いメソッド
次に使用頻度が高く便利なメソッドを紹介します。
add | 追加
addメソッドはListに要素を追加する際に使用します。
下図の実行結果から分かるように、addメソッドはListの最後尾に値が追加されます。
List<String> list1 = new ArrayList<>();
list1.add("aaa");
list1.add("bbb");
System.out.println(list1);
// [aaa, bbb]
addメソッドの引数に追加したいデータを記述することでListに値が追加されます。
特定の場所に、値を追加したい場合は、以下のように書き換えます。
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add(1, "ccc");
System.out.println(list);
// [aaa, ccc, bbb]
addメソッドの第1引数に追加したい場所、第2引数に追加する値を記述します。
addAll | まとめて追加
まとめて値をListに格納したい場合は、Collections.addAllメソッドを使うと楽に追加出来ます。
第1引数に対象のList、第2引数以降に追加したい値を記述します。
List<String> list = new ArrayList<>();
Collections.addAll(list, "aaa", "bbb", "ccc");
System.out.println(list);
// [aaa, bbb, ccc]
また、addAllメソッドは、List同士の結合も可能です。
List<String> list1 = new ArrayList<>();
Collections.addAll(list1, "aaa", "bbb", "ccc");
List<String> list2 = new ArrayList<>();
Collections.addAll(list2, "ddd", "eee", "fff");
list1.addAll(list2);
System.out.println(list1);
// [aaa, bbb, ccc, ddd, eee, fff]
set | 変更
setメソッドは、既にListに格納されている値を書き換えることができます。
List<String> list1 = new ArrayList<>();
list1.add("aaa");
list1.add("bbb");
list1.set(0, "ccc");
System.out.println(list1);
// [ccc, bbb]
setメソッドの第1引数には、変更したい要素のindexを指定します。
第2引数には、変更後の値を記述します。
ちなみに、第1引数で指定するindexが存在しない場合はエラーが発生するので注意。
get | 値の取得
getメソッドでは引数で指定したindexの値を取得できます。
戻り値はListではなく、Listの中の要素の型になります。
List<String> list1 = new ArrayList<>();
list1.add("aaa");
list1.add("bbb");
System.out.println(list1.get(1));
// bbb
size | 要素数を取得
sizeメソッドは、Listの中にある要素の数を取得することができます。
戻り値は、int型になります。for文の条件式に使われることが多いです。
List<String> list1 = new ArrayList<>();
list1.add("aaa");
list1.add("bbb");
System.out.println(list1.size());
// 2
contains | 存在確認
containsメソッドは、Listの中に引数で指定した値が含まれるか確認できます。
戻り値はboolean型になります。よくif文の条件式に使用されます。
List<String> list1 = new ArrayList<>();
list1.add("aaa");
list1.add("bbb");
System.out.println(list1.contains("aaa"));
// true
isEmpty | 空かどうか確認
isEmptyメソッドは、Listの中に要素が入っていないか確認することができます。
空の場合はtrue、空ではない場合はfalseになります。
こちらもif文の条件式でよく使用されます。
List<String> list1 = new ArrayList<>();
list1.add("aaa");
list1.add("bbb");
System.out.println(list1.isEmpty());
// false
Listを使ったテクニック
いろいろなテクニックをいくつか紹介します。
Listの中にListを入れる
以下のサンプルコードでは、Listの中にListを入れています。
List<List<String>> lists = new ArrayList<>();
List<List<Integer>> lists = new ArrayList<>();
階層的になったListを取り出す方法は以下の通りです。
List<List<String>> lists = new ArrayList<>();
lists.add(List.of("aaa", "bbb"));
lists.add(List.of("ccc", "ddd"));
System.out.println(lists.get(0).get(1));
// bbb
3行目のList.ofは長さ(length)が固定のListを作成できます。
add(追加)やremove(削除)ができなくなりますので、注意してください。
また、nullを入れることもできません。
拡張for文で値を取り出す
値をすべて取り出したい場合は、拡張for文が便利です。
ただし、removeメソッド(削除)を使用する場合は注意してください。
拡張for文を使う場合は、removeメソッドを使用しないのが無難です。
List<String> lists = new ArrayList<>();
lists.add("aaa");
lists.add("bbb");
for (var list : lists) {
System.out.println(list);
}
// aaa
// bbb
iteratorを使用する
イテレーターを使用することで拡張for文のように繰り返し処理を実現できます。
hasNext()は次の要素がある場合にtrueになります。
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
Iterator<String> ite = list.iterator();
while (ite.hasNext()) {
System.out.println(ite.next());
}
// aaa
// bbb
Listの中にクラスを入れる
Listの中には基本的にどんな型でも入れることができます。
※int型などのプリミティブ型は不可(IntegerであればOK)
クラスも型ですので、Listの中に入れることができます。
まずは、リストに格納するクラスを作成します。
package java20230808;
public class Data {
private int num;
private String str;
// setterとgetterの定義
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
次に、Mainクラスを作成します。
package java20230808;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
// Dataクラスのインスタンス(data1)を作成し、値をセット
Data data1 = new Data();
data1.setNum(1);
data1.setStr("apple");
// Dataクラスのインスタンス(data2)を作成し、値をセット
Data data2 = new Data();
data2.setNum(2);
data2.setStr("banana");
// リストに上で作成した2つのインスタンスを格納
List<Data> dataList = new ArrayList<>();
dataList.add(data1);
dataList.add(data2);
// 拡張for文でDataクラスの中に入っている値を取り出す
for (Data data : dataList) {
System.out.println(data.getNum() + ":" + data.getStr());
}
}
}
これで実行すると、結果は以下のようになります。
1:apple
2:banana
このようにクラスもリストに格納することができます。
最初は難しく感じますが、慣れると便利で使用する場面も多々ありますので
覚えておくといいと思います。
LinkedListについて
冒頭で少し、LinkedListについて触れたので、少し解説します。
LinkedListは、ArrayListと非常に似ていますが、構造が異なります。
そのため、それぞれに違いやメリットとデメリットがあります。
内部実装
ArrayListは、内部的に配列を使用して値の格納を行います。
値の追加や削除が行われるたびに、内部の配列のサイズを調整しています。(可変長配列)
一方で、LinkedListは双方向リンクリストを使用して値を格納しています。
各値は、前後の要素の参照を保持しているため、値の追加や削除が効率的になります。
そのため、値の追加や削除を目的とするListの場合はLinkedListが有効な場合が多いです。
アクセス効率
ArrayListは、値が順序を保持しているため、List内のランダムな値へのアクセス速度は速いです。
値のインデックス(順序)を指定したい場合は、ArrayListが有効です。
LinkedListは、値が順序を保持しているわけではなく、前後を見なければいけないため、
ランダムな値へのアクセス速度は遅くなります。
ただし、先頭から順番にたどるような操作にはLinkedListが有効です。
追加/削除の効率
ArrayListは、値の追加や削除をする場合に後続の値をずらす必要があるため、
追加や削除の操作には向いていません。
一方でLinkedListは、前後の値のリンクを変更するだけなので効率よく操作が可能です。
メモリ使用量
ArrayListは、内部的に配列を使用するため、
値の追加や削除が頻繁に行われる場合でも、メモリの再割り当てが発生しません。
LinkedListは、各値が自身の前後の値への参照を持つため、余分なメモリが必要になります。
また、値ごとに参照用のオブジェクトが追加されるため、
ArrayListよりもメモリ使用量が多くなる場合があります。
まとめ
ここまでListについて、紹介しました。
工夫次第で便利な使い方ができるので、色々試してみてください。
読んでいただき、ありがとうございます。
コメント