S-JIS[2007-03-26/2023-09-24] 変更履歴
Javaのリストやマップ等のコレクション(要素の集合・グループ)クラス。
|
|
|
| コレクション | クラス | 備考 | 旧クラス | 更新日 |
|---|---|---|---|---|
| リスト | List | リストのインターフェース。 | ||
| LinkedList | いわゆる普通の双方向リスト。 | |||
| ArrayList | インデックスを使って途中の要素にアクセスするのが高速なリスト。 ただし途中の要素の追加・削除は遅い。 →MTセーフなArrayList |
Vector | ||
| SortedList | 自動的にソートされるリスト、というものは無い。 (重複無しなら)TreeSetを使うか、Collections#sort()でソートする。 |
2008-07-05 | ||
| emptyList() | 常に空のリスト。→空のコレクション | EMPTY_LIST | 2008-07-09 | |
| BitSet | booleanの可変長配列のようなもの。 インデックスを使ったアクセスを行うが、Listは実装していない。 名前は「Set」だが、Setは実装していない。 |
2010-02-13 | ||
| マップ | Map | 連想配列(マップ)のインターフェース。 | ||
| HashMap | hashCode()を利用したマップ。 →HashMapの仕組み →HashMapのキーについての注意点 →MTセーフなHashMap |
Hashtable | ||
| SortedMap | キーがソートされるマップ(インターフェース)。 具象クラスはTreeMap。 |
2008-07-05 | ||
| NavigableMap | (完全一致でなく、)近いキーを取得できるマップ(インターフェース)。 具象クラスはTreeMap。 |
2008-07-24 | ||
| TreeMap | キーがソートされるマップ(実体)。 | |||
| LinkedHashMap | キーの順序がputした順番であることが保証されているマップ。 同じキーをputした場合、順序は最初にputした位置で、値は後からputしたものになる。 |
2008-07-05 | ||
| emptyMap() | 常に空のマップ。→空のコレクション | EMPTY_MAP | 2008-07-09 | |
| EnumMap | 列挙型をキーにとる場合に効率がよいマップ。JDK1.5以降。 | |||
| Properties | プロパティー(プロパティーファイルの内容) | |||
| WeakHashMap | キーを弱参照で保持するハッシュマップ | 2008-07-14 | ||
| DoubleOrderedMap | Apache commonsの双方向マップ。 つまり値を指定してキーを取得する事も出来る。 |
2010-02-13 | ||
|
BiMap HashBiMap |
google-collectionsの逆方向マップを取得できるマップ。 | 2010-02-13 | ||
| セット (集合) |
Set | セット(マップに対し、キーだけを保持するような物)のインターフェース。 | ||
| HashSet | HashMapのキーのセット。 | |||
| SortedSet | ソートされているSetのインターフェース。 | 2008-07-05 | ||
| TreeSet | TreeMapのキーのセット。(ソートされている) | |||
| emptySet() | 常に空のセット。→空のコレクション | EMPTY_SET | 2008-07-09 | |
| EnumSet | 列挙型の論理和を保持する為のセット。JDK1.5以降。 | |||
| BitSet | 名前は「Set」だが、Setの具象クラスではない。 | 2010-02-13 | ||
| スタック | LinkedList | LinkedListは双方向リストであってスタックではないのだが、synchronizedで同期化されていないスタッククラスは無い模様。 (Stackクラスは 何故かVectorを継承していてsynchronizedで同期化されている為、重い) そこで、LinkedListで代用する。 push→add、pop→removeLastでOK。 (ただしremove系は、値が存在しないと例外が発生する) |
Stack | 2007-06-12 |
| ArrayDeque | (JDK1.6以降) 配列を使って実装されているので、スタックの最大数が変わらないならLinkedListより高速。 (最大数が変わると拡張処理が発生する) push→addLast、pop→pollLast または push→addFirst、pop→pollFirst |
2009-01-04 | ||
| キュー | Queue | キューのインターフェース(JDK1.5以降) 追加はadd又はoffer、取得はremove又はpoll(例外を返すかどうかが異なる)。 |
JDK1.4までは、Queue自体、コレクションクラスとしては用意されていなかった。 | 2007-12-07 |
| LinkedList | 追加→addLast(add)、取得→removeFirst(poll) | 2008-07-07 | ||
| LinkedBlockingQueue | 2008-07-24 | |||
| ArrayBlockingQueue | 2008-07-24 | |||
| 双方向キュー | Deque | 双方向キューのインターフェース(JDK1.6以降) 「デック」と読むらしい。 |
2008-07-24 | |
| ArrayDeque | (キューに溜める最大数が固定なら)LinkedListより高速。 (配列内の開始位置と終了位置を保持してずらすので、ArrayListをキューに使うのと違って効率が良い) |
2009-01-04 | ||
| LinkedList | 2008-07-24 | |||
| LinkedBlockingDeque | 2008-07-24 |
Verctor・Hashtableは、それぞれArrayList・HashMapのMTセーフバージョンという位置づけ。
すなわち、ほとんどの操作メソッドがsynchronizedで同期化されているので、動作が遅い。
マルチスレッドで複数のスレッドから同一のコレクションインスタンスにアクセスしない限り
MTセーフ版を使う必要は無いので、普通はArrayListやHashMapを使うのがよい。
仮にMTセーフ版を使う必要があるとしても、JDK1.5で追加された、より高速なMTセーフなコレクションを使った方が良さげ。
JDK1.5から、リストやマップは総称型を使うようにコードが書き換えられた。[2007-05-02]
JDK1.4までは、String型のみを扱いたいと思っても(Object型なので)何でも入れられたので、プログラマーが気をつける必要があった。
総称型が導入されたことで、違う型で扱おうとするとコンパイルエラーになるので間違いが発見しやすくなった。
(Object型から目的の型へのキャストも減って、コーディングもすっきりするようになった)
List<String> list = new ArrayList<String>(); //String限定のリスト
list.add("abc");
String s = list.get(0);
Map<String,Integer> map = new HashMap<String,Integer>(); //キーがString、値がIntegerのマップ
map.put("abc", new Integer(123));
Integer i = map.get("abc");
プリミティブ型を指定することは出来ないが、JDK1.5からは自動ボクシングという機能も導入されたので、ラッパークラスを指定すれば( ソース上の見た目としては)扱える。
Map<String,Integer> map = new HashMap<String,Integer>(); //キーがString、値がIntegerのマップ
map.put("abc", 123);
int i = map.get("abc");
Iteratorもコレクションクラスの型を引き継いでくれる。[2007-06-11]
//リスト
for (Iterator<String> i = list.iterator(); i.hasNext();) {
String val = i.next();
System.out.println(val);
}
for (String val : list) {
System.out.println(val);
}
//マップ
for (Iterator<String> i = map.keySet().iterator(); i.hasNext();) {
String key = i.next();
System.out.println(map.get(key));
}
for (String key : map.keySet()) {
System.out.println(map.get(key));
}
また、限定する型を指定しない(JDK1.4までのような)やり方も今までどおり使う事が出来る。
(コンパイルすると警告(unchecked)が出るけど)
java.util.Collectionsクラスに、空のコレクション(リスト・マップ・セット)のインスタンスが用意されている。[2008-07-09]
中身が空のコレクションは、これらを使うことが出来る。
例えばリスト(EMPTY_LIST)の場合、以下のようにして使用する。
List list = Collections.EMPTY_LIST;
System.out.println(list.size()); //常に0
//× list.add("abc"); //常にUnsupportedOperationExceptionが発生する
//× Object obj = list.get(0); //常にIndexOutOfBoundsExceptionが発生する
マップ(EMPTY_MAP)なら、get()は常にnullを返す、という具合。
つまり、値取得系のメソッドは値が無い状態の動作をし、値をセットする系統のメソッドは例外が発生するので 常に“空の状態”が保たれる、というわけ。
ところで、JDK1.5でコレクションクラスは総称型を使用するようになった為、EMPTY_LISTやEMPTY_MAPを直接使うと、キャストに関して警告が出てしまう。
List<String> list = (List<String>)Collections.EMPTY_LIST; //「実際には消去された型Listに対してチェックを行います」という警告
そこで、指定した型の空コレクションを返すメソッド(emptyList()・emptyMap()・emptySet())が用意された。
例えばリスト(emptyList())の場合、以下のようにして使用する。
List<String> slist = Collections.emptyList(); List<Integer> ilist = Collections.emptyList();
実際に返って来ているのはEMPTY_LISTそのまま。
emptyList()の定義にはメソッドの総称型が使用されているので、変数宣言に書いた<型>に応じて自動的に“キャストされたEMPTY_LIST”になってくれる。
空のコレクション(リスト等)そのものは、上記のようにCollections.emptyList()の代入先に合わせて型引数が指定される。[2009-02-09]
しかしそのIteratorを直接取ろうとすると、そのままでは出来ない。
Iterator<String> i = Collections.emptyList().iterator(); // キャストできないというコンパイルエラー Iterator<?> j = Collections.emptyList().iterator(); // OK Iterator<Object> k = Collections.emptyList().iterator(); // OK
ワイルドカード<?>や<Object>は大丈夫だが、それではあまり嬉しくない…。
こういう場合は、明示的な型指定を使うと良い。
Iterator<String> i = Collections.<String>emptyList().iterator(); // OK
public Iterator<String> getIterator() {
if (this.list == null) {
return Collections.<String>emptyList().iterator();
} else {
return this.list.iterator();
}
}
Java9で、List・Set・Mapにofメソッドが追加された。[2017-09-24]
引数なしのofメソッドを使うと、空の不変コレクションが作れる。
| コレクション | JDK1.5 | JDK9 |
|---|---|---|
| リスト | Collections.emptyList() |
List.of() |
| セット | Collections.emptySet() |
Set.of() |
| マップ | Collections.emptyMap() |
Map.of() |
ただし、Collectionsの空クラスとofメソッドの空クラスは実装が異なる。
動作も若干異なっており、例えばclearメソッドを呼び出すと、Collectionsの空クラスでは何もしないが、ofメソッドの空クラスはUnsupportedOperationExceptionが発生する。
空のコレクションと似た感じで、値を1つだけ持つ(変更不能な)コレクションを作ることが出来る。[2008-07-09]
Java9では、
引数が1個のofメソッドを使うと、値を1つだけ持つ不変コレクションが作れる。[2017-09-24]
| コレクション | JDK1.5 | JDK9 | 備考 |
|---|---|---|---|
| リスト | Collections.singletonList(T obj) |
List.of(obj) |
|
| セット | Collections.singleton(T obj) |
Set.of(obj) |
なんでsingletonSet()って名前じゃないんだろう? |
| マップ | Collections.singletonMap(K key, V value) |
Map.of(key, value) |
List<String> list = Collections.singletonList("abc");
System.out.println(list.size()); //常に1
for (String s : list) {
System.out.println(s);
}
このsingletonシリーズも 値の変更が不可能。
つまり「list.set(0,"zzz")」等の呼び出しを行うとUnsupportedOperationExceptionが発生する。
…しかし、値が1個しか入ってないコレクション(集合)って、あまり使い道が思い浮かばないなぁ…。 でもまぁ、デフォルトで唯一の値を持っているリストとかマップとかを作ることはあるのかも。
1つだけ値を持つコレクションの汎用化版と言うか、内容を変更できないコレクションを作ることが出来る。[2008-07-09]
ちなみにJava9では、ofメソッドを使うと、値を指定して不変コレクションが作れる。[2017-09-24]
| コレクション | メソッド | JDK9 |
|---|---|---|
| リスト | Collections.unmodifiableList(List) |
List.of(obj1, obj2, …) |
| セット | Collections.unmodifiableSet(Set) |
Set.of(obj1, obj2, …) |
| マップ | Collections.unmodifiableMap(Map) |
Map.of(k1, v1, k2, v2, …) |
| 一般 | Collections.unmodifiableCollection(Collection) |
Collectionsのメソッドは 引数の種類(型)が全部違うんだから、メソッド名を同じにしてオーバーロードを作っても良さそうな気がするんだけど、そうしない理由があるのかな?
普通にリストを作ってunmodifiableList()を通すことにより、不変のリストが作られる。
private static final List<String> CONST_LIST;
static {
List<String> list = new ArrayList<String>(2);
list.add("abc");
list.add("def");
CONST_LIST = Collections.unmodifiableList(list);
}
static void sample() {
System.out.println(CONST_LIST.size());
for (int i = 0; i < CONST_LIST.size(); i++) {
System.out.println(CONST_LIST.get(i));
}
//× CONST_LIST.add("zzz"); //常にUnsupportedOperationExceptionが発生する
}
この不変リストの実体はラッパークラスであり、値を取得する系統のメソッドは元のリストの同メソッドを呼び出し、内容を変更する系統のメソッドは例外が発生するようになっている。
また、元のリストがRandomAccessインターフェースを実装していれば、不変リスト(ラッパークラス)もRandomAccessをimplementsしたクラスが使われる。
つまり、「if (list instanceof RandomAccess)」による判断はそのまま出来るということだ。ちょっと親切かも。あまり使うことは無さそうな気はするが(爆)
この不変用ラッパークラスは、元のリストを保持している。
したがって、元のリストの内容を変更すれば、不変リストの方も変更された値が取得できる。
このunmodifiableシリーズはけっこう便利そうだ。
値の変更は自分のみが行い、他人に変更させたくない場合もクローンを作らずに返せるわけだから。
private final List<String> privateList = new ArrayList<String>();
private final List<String> publicList = Collections.unmodifiableList(privateList);
/**
* リスト取得.
* @return リスト(必ずnull以外。このリストは変更できない)
*/
public List<String> getList() {
return publicList;
}
private void addList(String str) {
privateList.add(str);
}
Java21で、順序付きコレクションが導入された。[2023-09-23]
ListやDeque(双方向キュー)等の順序を持つCollectionにはSequencedCollectionインターフェースを実装している。
Setは基本的に順序を持たないが、順序を持つLinkedHashSetやTreeSetは(SequencedCollectionを継承している)SequencedSetインターフェースを実装している。
MapもSetと同様だが、要素の種類が異なるので、(SequencedCollectionを継承していない)SequencedMapを実装している。
| メソッド | 説明 |
|---|---|
| SequencedCollection<E> reversed() | 逆順のコレクションを返す。 |
| void addFirst(E) | コレクションの先頭に要素を追加する。 |
| void addLast(E) | コレクションの末尾に要素を追加する。 |
| E getFirst() | コレクションの先頭要素を取得する。 |
| E getLast() | コレクションの末尾要素を取得する。 |
| E removeFirst() | コレクションの先頭要素を削除して返す。 |
| E removeLast() | コレクションの末尾要素を削除して返す。 |
| メソッド | 説明 |
|---|---|
| SequencedMap<K, V> reversed() | 逆順のMapを返す。 |
| Map.Entry<K,V> firstEntry() | Mapの先頭Entryを返す。 |
| Map.Entry<K,V> lastEntry() | Mapの末尾Entryを返す。 |
| Map.Entry<K,V> pollFirstEntry() | Mapの先頭Entryを削除して返す。 |
| Map.Entry<K,V> pollLastEntry() | Mapの末尾Entryを削除して返す。 |
| V putFirst(K, V) | Mapの先頭にputする。 |
| V putLast(K, V) | Mapの末尾にputする。 |
| SequencedSet<K> sequencedKeySet() | keySet()のSequencedSet版。 |
| SequencedCollection<V> sequencedValues() | values()のSequencedCollection版。 |
| SequencedSet<Map.Entry<K, V>> sequencedEntrySet() | entrySet()のSequencedSet版。 |