JavaのListは、Java Collections Frameworkに属するインタフェースです。
java.util.Collectionを継承しており、Collectionが提供するメソッドを利用することができます。Listインタフェースは、複数の要素を順序付けをして格納することができ、要素の重複を許容するという特徴があります。配列のように添字で要素の順序を管理しますが、配列と違って要素数は動的で要素の追加、削除が自由にできます。
Listのインタフェースですから、実装はそのサブクラスが担っています。実装クラスは以下のようなものがあります。
ArrayListはサイズ変更可能な可変長配列として実装されており、リストへの要素の追加や削除に応じて動的に拡大・縮小することができます。要素へのアクセスは高速ですが、リストの途中からの要素の挿入や削除に時間がかかることがあります。
一方、LinkedListは連結リストとして実装されており、要素を含むノードの集合と、リスト内の前後のノードへの参照で構成されています。LinkedListは要素の挿入と削除は高速に行うことができますが、要素へのアクセスは遅くなってしまいます。
Vectorは、ArrayListと同様に可変長配列です。スレッドセーフなコレクションなのでマルチスレッド環境を要しない限りArrayListを使うほうがパフォーマンスが良くなります。
インタフェースから直接オブジェクトを作成することができないので、Listインタフェースを利用するには実装したクラスを使います。例えば、ArrayListクラスを使うと、次のようなリストを作成することができます。
class Main {
public static void main(String[] args) {
// ArrayListを初期化しList型で扱うリストの作成
java.util.List<Integer> list = new java.util.ArrayList<>();
}
}
この例では、ArrayListクラスを使って新しいインスタンスを作成し、それをList型で扱うことを宣言しています。ArrayListやListなどのコレクションはjava.utilパッケージに属しています。java.util.Listやjava.util.ArrayListは完全修飾クラス名といい、一般的には完全修飾クラス名を使わず、それぞれimportして利用します。
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
class Main {
public static void main(String[] args) {
// ArrayListを初期化しList型で扱うリストの作成
List<Integer> arrayList = new ArrayList<>();
// LinkedListを初期化しList型で扱うリストの作成
List<Integer> linkedList = new LinkedList<>();
}
}
ArrayListとLinkedListはどちらもListインターフェースを実装したクラスで、Listインターフェースのメソッドの具体的な実装を提供します。これらのクラスのいずれかを使用してリストを作成し、コード内で使用することができます。
Listインタフェースには、リスト内の要素を操作するためのメソッドがいくつか用意されています。最もよく使われるメソッドをいくつか紹介します。
ここでは、これらのメソッドの一部を使用する例を紹介します。
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
System.out.println(list.get(1)); // "Banana"
list.remove(2);
System.out.println(list); // "[Apple, Banana]"
list.set(0, "Mango");
System.out.println(list); // "[Mango, Banana]"
}
}
Listインタフェースが継承しているCollectionインタフェースは、Iterableインタフェースを継承しています。Iterableインタフェースは拡張for文を使うために用意されています。Listをforでループするには、通常のfor文よりも拡張for文を使ったほうがパフォーマンスが良くなります。
import java.util.ArrayList;
import java.util.List;
class Main {
public static void printList(List<String> list) {
for(String s: list) {
System.out.println(s);
}
}
public static void main(String[] args) {
List<String> fruits = new ArrayList<String>();
fruits.add("apple");
fruits.add("banana");
fruits.add("orange");
fruits.add("kiwi");
printList(fruits);
}
}
先ほどArrayListで作成したコードをLinkedListに変更してみましょう。
import java.util.LinkedList;
import java.util.List;
class Main {
public static void printList(List<String> list) {
for(String s: list) {
System.out.println(s);
}
}
public static void main(String[] args) {
List<String> fruits = new LinkedList<String>();
fruits.add("apple");
fruits.add("banana");
fruits.add("orange");
fruits.add("kiwi");
printList(fruits);
}
}
このコードではInteger型の要素を扱うLinkedListを初期化し、それをList型のfruitsという変数で扱うと宣言するように変更されました。ArrayListからLinkedListに変更しましたが、List型で扱うと宣言しているためリストを操作する処理を変更する必要はありません。利用する側のコードを変更することなく仕様変更に対応できる点が、List型で宣言するメリットです。