Mapのキーや値を取得して繰り返し処理を行いたい場合、EnumerationもしくはIteratorを使う。 どちらもjava.util配下のインタフェースである。
IteratorはEnumerationの改良版であり、Enumerationは古くからあるAPIでしか使用されていない。 Enumerationの公式Javadocにも、新しく実装する場合にはIteratorを使うよう言及されている。
では何が改良されたのか?これはIterator側のJavadocに記載されている。
メソッド | Enumeration | Iterator |
---|---|---|
要素の有無判定 | hasMoreElements() | hasNext() |
次の要素取得 | nextElement() | next() |
要素削除 | - | remove() |
このようにIteratorではメソッド名が短くなっているのと、要素削除メソッドが追加されている。
では、EnumerationとIteratorのサンプルコードを使って動作を確認してみる。
まずはHashMapのキーと値を標準出力に表示。
Mapインタフェースには直接Enumerationで取得するメソッドがないため、Collections.enumeration()を使う。
Map<String, String> map = new HashMap();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
map.put("key5", "value5");
Enumeration<String> keys = Collections.enumeration(map.keySet());
while(keys.hasMoreElements()) {
System.out.println(keys.nextElement());
}
Enumeration<String> values = Collections.enumeration(map.values());
while(values.hasMoreElements()) {
System.out.println(values.nextElement());
}
出力結果
key1
key2
key5
key3
key4
value1
value2
value5
value3
value4
キーと値が出力されているのがわかる。HashMapは順序性を持たないので、設定した順と関係なく、順不同で表示されている。
次はHashtableで試してみる。HashtableはキーのみEnumerationで取得するkeysメソッドが用意されている。
Hashtable<String, String> hashT = new Hashtable();
hashT.put("key1", "value1");
hashT.put("key2", "value2");
hashT.put("key3", "value3");
hashT.put("key4", "value4");
hashT.put("key5", "value5");
Enumeration<String> keys = hashT.keys();
while(keys.hasMoreElements()) {
System.out.println(keys.nextElement());
}
Enumeration<String> values = Collections.enumeration(hashT.values());
while(values.hasMoreElements()) {
System.out.println(values.nextElement());
}
出力結果
key5
key4
key3
key2
key1
value5
value4
value3
value2
value1
Hashtableも順不同で表示されている。
次はLinkedHashMapで試してみる。使い方はほぼHashMapと同じ。
Map<String, String> map = new LinkedHashMap();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
map.put("key5", "value5");
Enumeration<String> keys = Collections.enumeration(map.keySet());
while(keys.hasMoreElements()) {
System.out.println(keys.nextElement());
}
Enumeration<String> values = Collections.enumeration(map.values());
while(values.hasMoreElements()) {
System.out.println(values.nextElement());
}
出力結果
key1
key2
key3
key4
key5
value1
value2
value3
value4
value5
LinkedHashMapは順序性を保つので、設定した順番に出力される。
最後に繰り返し処理中に要素を削除してみる。Enumeration自体には削除メソッドがないため、Mapのremoveメソッドで削除。
Map<String, String> map = new HashMap();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
map.put("key5", "value5");
Enumeration<String> keys = Collections.enumeration(map.keySet());
while(keys.hasMoreElements()) {
String key = keys.nextElement();
if("key3".equals(key)){
map.remove(key);
}
System.out.println(key);
}
出力結果
key1
key2
key5
key3
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(Unknown Source)
at java.util.HashMap$KeyIterator.next(Unknown Source)
at java.util.Collections$3.nextElement(Unknown Source)
at Sample.sampleRemoveData(Sample.java:92)
at Sample.main(Sample.java:11)
削除する時に例外が発生する。この例外は要素の整合性が保てなくなった際に発生する例外である。このようにEnumerationを使うと繰り返し中に要素の削除ができない。
次にIteratorのサンプル。
まずは先ほどと同様HashMapのキーと値を標準出力に表示してみる。
MapインタフェースのkeySet()、values()の戻り値がCollectionインタフェースを実装しているため、Collectionのiterator()を使ってIteratorを取得する。
Map<String, String> map = new HashMap();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
map.put("key5", "value5");
Iterator<String> keys = map.keySet().iterator();
while(keys.hasNext()) {
System.out.println(keys.next());
}
Iterator<String> values = map.values().iterator();
while(values.hasNext()) {
System.out.println(values.next());
}
出力結果
key1
key2
key5
key3
key4
value1
value2
value5
value3
value4
結果はEnumerationの時と同様。
次はHashtableで試してみる。キーはkeys()ではなくkeySet()を使う。
Hashtable<String, String> hashT = new Hashtable();
hashT.put("key1", "value1");
hashT.put("key2", "value2");
hashT.put("key3", "value3");
hashT.put("key4", "value4");
hashT.put("key5", "value5");
Iterator<String> keys = hashT.keySet().iterator();
while(keys.hasNext()) {
System.out.println(keys.next());
}
Iterator<String> values = hashT.values().iterator();
while(values.hasNext()) {
System.out.println(values.next());
}
出力結果
key5
key4
key3
key2
key1
value5
value4
value3
value2
value1
HashtableもEnumerationと同様の出力結果となる。
次はLinkedHashMap。
Map<String, String> map = new LinkedHashMap();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
map.put("key5", "value5");
Iterator<String> keys = map.keySet().iterator();
while(keys.hasNext()) {
System.out.println(keys.next());
}
Iterator<String> values = map.values().iterator();
while(values.hasNext()) {
System.out.println(values.next());
}
出力結果
key1
key2
key3
key4
key5
value1
value2
value3
value4
value5
LinkedHashMapもEnumerationと同様の出力結果。
ここまではEnumerationとIteratorで動きに違いはない。
では次に要素の削除を実施してみる。Iteratorのremoveメソッドを使って削除する。
コードMap<String, String> map = new HashMap();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
map.put("key5", "value5");
Iterator<String> keys = map.keySet().iterator();
while(keys.hasNext()) {
String key = keys.next();
if("key3".equals(key)){
keys.remove();
}
System.out.println(key);
}
System.out.println(map);
出力結果
key1
key2
key5
key3
key4
{key1=value1, key2=value2, key5=value5, key4=value4}
例外は発生せず、うまく削除できた。Enumerationと比べてIteratorの方が使い勝手がよくなっていることがわかる。