Java コレクションフレームワーク
Javaコレクションフレームワークは、多数のデータをまとめて管理および処理するために用意されたもので、様々なタイプのインタフェースとクラスで構成されています。
これらのインタフェースはjava.util.Collectionとjava.util.Mapの2つのグループに分けることができます。
- Collection
- List
- Set
- Queue
- Deque
- Map
MapはCollectionを継承していないため狭義の意味ではコレクションではありませんが、Mapが持つ3つのコレクションビューにより、コレクション(データの集合)として扱うことができます。
コレクションフレームワークは、データ構造とアルゴリズムが提供されているため、開発コストの削減や、パフォーマンスの向上、設計コストの削減などのメリットがあります。
Java Collectionインタフェース
Collectionインタフェースは、複数の要素を保持するためのインタフェースです。Collectionは、List, Set, Queueなどのサブインタフェースを持ち、それらはそれぞれ異なる特徴を持っています。
- List: 順序付きリストのインタフェース
- Set: 重複を許さない集合のインタフェース
- Queue: 多くの場合FIFOで要素の順序付けを行うインタフェース
- Deque: 両端から要素の挿入及び削除を行うインタフェース
Collectionインタフェースは、以下のようなメソッドを持っています。
- add(E e): 要素を追加する
- remove(Object o): 指定された要素を削除する
- contains(Object o): 指定された要素がコレクションに含まれているかどうかを返す
- isEmpty(): コレクションが空かどうかを返す
- size(): コレクションの要素数を返す
- iterator(): コレクションを反復処理するためのイテレータを返す
これらのメソッドは実装がなく、サブクラスで実装されています。
また、Collectionインタフェースは、java.langパッケージのjava.lang.Iterableインタフェースを継承しています。Iterableインタフェースは、Javaで拡張for(for-each)文を使用できるようにするためのインタフェースです。Collectionインタフェースを実装したクラスはすべて、for-each文でループすることができます。
インターフェースについては、OOPコースで詳しく学べます。
Java Listインタフェース
Listインタフェースは順序付きリストのコレクションで、インデックスによってリスト内の要素にアクセスすることができます。以下のクラスで実装されています。
- ArrayList
- LinkedList
- Vector
- Stack
VectorとStackは古くからあるレガシーなクラスです。非推奨の指定はされていませんが、新しいコードでは代わりのクラスを使うよう勧められています。Vectorはスレッドセーフが必要な場合はCollections.synchronizedListを使用し、それ以外はArrayListを使うほうがパフォーマンスが良くなります。StackについてはDequeを使用するよう推奨されています。
ListとArrayListは以下のように使います。
// パッケージをimportします
import java.util.List;
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
// AbstractCollectionで実装されているtoString()メソッドが呼ばれるので[]の中に要素が表示される
System.out.println(list);
// インデックスを保持するためget(インデックス番号)で要素を取得
System.out.println(list.get(1));
// iterableインタフェースを継承しているので拡張for文が使えます
for(Integer i: list) {
System.out.println(i);
}
}
}
Java Setインタフェース
Setインタフェースは、Javaプログラミング言語におけるデータ構造の1つで、複数の要素を保持するコレクションを表します。Setは、重複を許さないという特徴があります。要素の順序は実装クラスによって異なり、HashSetは順序を保証せず、LinkedHashSetは追加した順序、TreeSetはソートされた順序を保持します。Collectionを継承しているため、Collectionインタフェースに定義されているすべてのメソッドを使用することができます。
Setインタフェースを実装するクラスとしては、HashSetやTreeSetがあります。HashSetは、ハッシュテーブルを使用して要素を保存し、TreeSetは、集合内の要素を自然順序、または生成時に指定したComparatorの順序で保持します。内部の実装は、実際はMapインタフェースの実装クラスであるHashMapやTreeMapの実装へ処理を委譲しています。
Java Queueインタフェース
Queueインタフェースは、Javaプログラミング言語におけるデータ構造の1つで、処理を待つ要素を保持するためのインタフェースです。多くの実装は先入れ先出し(FIFO)で要素を取り出しますが、PriorityQueueのように優先度順に取り出す実装もあります。Collectionインタフェースを継承しているため、Collectionインタフェースに定義されているすべてのメソッドを使用することができます。
Queueインタフェースは、以下のようなメソッドを持っています。
- offer(E e): 要素をエンキューする
- poll(): 先頭の要素をデキューして取り出す
- peek(): 先頭の要素を参照する
Queueインタフェースを実装するクラスとしては、LinkedListやArrayDequeがあります。
import java.util.ArrayDeque;
import java.util.Queue;
class Main {
public static void main(String[] args) {
// ArrayDequeを使用したQueueの生成
Queue<String> queue = new ArrayDeque<>();
// 要素のエンキュー
queue.offer("Alice");
queue.offer("Bob");
queue.offer("Charlie");
queue.offer("Dave");
// キューのサイズを取得
int size = queue.size();
System.out.println("Queue size: " + size); // "Queue size: 4"
// 先頭の要素を参照
String head = queue.peek();
System.out.println("Head of queue: " + head); // "Head of queue: Alice"
// 要素のデキュー
while (queue.peek() != null) {
String s = queue.poll();
System.out.println("Dequeued: " + s);
}
// "Dequeued: Alice"
// "Dequeued: Bob"
// "Dequeued: Charlie"
// "Dequeued: Dave"
}
}
Java Dequeインタフェース
Deque(Double-ended queue)は、Javaプログラミング言語におけるデータ構造の1つで、双方向キューを表すインタフェースです。Dequeは、両端から要素を追加したり削除したりできるデータ構造です。Dequeは、単方向のQueueインタフェースと比べて、より柔軟な操作ができるインタフェースです。
Dequeインタフェースは、java.utilパッケージのjava.util.Queueインタフェースを継承しています。そのため、Queueインタフェースに定義されているすべてのメソッドを使用することができます。
Dequeインタフェースは、以下のようなメソッドを持っています。
- addFirst(E e):先頭に要素を追加する
- addLast(E e):末尾に要素を追加する
- offerFirst(E e):先頭に要素を追加する
- offerLast(E e):末尾に要素を追加する
- removeFirst():先頭の要素を削除する
- removeLast():末尾の要素を削除する
- pollFirst():先頭の要素を削除して取り出す
- pollLast():末尾の要素を削除して取り出す
Dequeインタフェースを実装するクラスとしては、ArrayDequeやLinkedListがあります。
import java.util.ArrayDeque;
import java.util.Deque;
class Main {
public static void main(String[] args) {
// ArrayDequeを使用したDequeの生成
Deque<String> deque = new ArrayDeque<>();
// 要素の追加
deque.addFirst("Alice");
deque.addLast("Bob");
deque.addLast("Charlie");
deque.addLast("Dave");
// Dequeのサイズを取得
int size = deque.size();
System.out.println("Deque size: " + size); // "Deque size: 4"
// 先頭の要素を参照
String head = deque.peekFirst();
System.out.println("Head of deque: " + head); // "Head of deque: Alice"
// 末尾の要素を参照
String tail = deque.peekLast();
System.out.println("Tail of deque: " + tail); // "Tail of deque: Dave"
// 要素の削除
while (deque.peekFirst() != null) {
String s = deque.pollFirst();
System.out.println("Dequeued from head: " + s);
}
// "Dequeued from head: Alice"
// "Dequeued from head: Bob"
// "Dequeued from head: Charlie"
// "Dequeued from head: Dave"
}
}
Java Mapインターフェース
Mapインタフェースは、Javaプログラミング言語におけるデータ構造の1つで、キーと値の組を保持するためのインタフェースです。Mapは、任意のオブジェクトをキーとして、任意の値を保持することができます。同じキーを使用して複数の値を保持することはできません。
Mapインタフェースは、以下のようなメソッドを持っています。
- put(K key, V value): キーと値の組をマップに追加する
- get(Object key): 指定されたキーに対応する値を取得する
- remove(Object key): 指定されたキーに対応する値を削除する
- containsKey(Object key): 指定されたキーがマップに含まれているかどうかを返す
- isEmpty(): マップが空かどうかを返す
- size(): マップに含まれるキーと値の組の数を返す
MapはCollectionインタフェースを継承していないので、Collectionで定義されたメソッドを使うことはできません。Mapインタフェースは、キーと値の組を保持するデータ構造ですが、そのキーや値を単独で参照することもできるように、コレクションビューを提供しています。
- keySet(): マップのキーを保持するSetを返す
- values(): マップの値を保持するCollectionを返す
- entrySet(): マップのキーと値の組を保持するSetを返す
Mapインタフェースを実装するクラスとしては、HashMapやTreeMapがあります。
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
class Main {
public static void main(String[] args) {
// HashMapの生成
Map<String, Integer> map = new HashMap<>();
// 要素の追加
map.put("Alice", 100);
map.put("Bob", 90);
map.put("Charlie", 80);
map.put("Dave", 70);
// キーを保持するSetを取得
Set<String> keySet = map.keySet();
// Setを繰り返し処理
for (String key : keySet) {
int value = map.get(key);
System.out.println(key + ": " + value);
}
// "Bob: 90"
// "Alice: 100"
// "Charlie: 80"
// "Dave: 70"
}
}