初出 JAVA PRESS Vol.26

Java API ダイジェスト

java.util.Map

MapインタフェースはJCFで策定されているインタフェースの中の1つです。Listインタフェースと同様にどのようなオブジェクトでも保持することができますが、プリミティブ型を保持するにはラッパクラスを使用します。

その特徴はキーでアクセスすることができることにあり、辞書のような用途に使用することができます。Mapインタフェースには順序はありませんが、整列順であれば派生インタフェースのSortedMapインタフェースが使用できます。

また、Mapインタフェースは同一のキーで要素を保持させることはできません。ただし、キーが異なれば、同じ要素でも保持することができます。


キーと要素の対応付け

要素の登録にはputメソッド、取得にはgetメソッドを使用します。また、削除はremoveメソッドです。どのメソッドもキーを使用して要素を指定します。

■ 要素へのアクセス

キーと要素の全体を取得するためのメソッドも定義されています。

keySetメソッドは使用されているキーの一覧を返します。キーは重複が許されていないため、戻り値はSetオブジェクトになります。

一方の valuesメソッドは要素の一覧を返します。要素は重複が許されているので、戻り値はCollectionオブジェクトになります。

■ キーと要素の取得

辞書を作成するためには

■ 要素へのアクセス

public Object put(Object key, Object value)

keyとvalueを対にしてマップに登録します。keyがすでに使用されていた場合は、要素がvalueに上書きされます。戻り値はkeyが使用されていなかった場合はnull、使用されていた場合は対応していた要素になります。

要素にはnullを使用することができますが、キーにnullが使用できるかどうかはMapインタフェースを実装したクラスに依存します。たとえばHashMapクラスではnullのキーを使用することができます。

リスト1はキーを英語、バリューに日本語にした辞書の例です。

リスト1 putの使用例
    public void initDictionary(Map dic) {
        dic.put("desk", "机");
        dic.put("book", "本");
        dic.put("paper", "紙");
    }

public Object get(Object key)

keyに対応する要素を取得します。戻り値はObjectなので、適当な型にキャストする必要があります。

keyに対応する要素がない場合はnullが戻ります。ただし、戻り値がnullの場合、keyに対応している要素がないのか、要素がnullなのか区別はできません。これを区別するにはcontainsKeyメソッドを使用してキーが使用されているかどうか調べる必要があります。

リスト2はリスト1で作成した辞書を引く例です。メソッドの戻り値がStringクラスなので、getメソッドの戻り値をSringクラスにキャストしています。

リスト2 getの使用例
    public String translateWord(Map dic, String key) {
        String result = (String)dic.get(key);
        return result;
    }

public Object remove(Object key)

keyに対応する要素をマップから削除します。戻り値はkeyに対応していた要素です。

keyに対応する要素がない場合はnullが戻ります。ただし、戻り値がnullの場合、getメソッドと同様に、keyに対応している要素がないのか、要素がnullなのか区別はできません。

■ キーと要素の取得

public Set keySet()

キーの一覧を取得できます。キーは重複が許されていないので、戻り値はSetオブジェクトになります。Setオブジェクトであれば、Iteratorオブジェクトに変換できるので、シーケンシャルアクセスが可能です。

public Collection values()

要素の一覧を取得できます。要素は重複している可能性があるので、戻り値はCollectionオブジェクトになります。keySetメソッドと同様にIteratorオブジェクトを得ることができるので、シーケンシャルアクセスができます。

リスト 3 はvaluesメソッドを使用したマップの全要素を出力する例です。

リスト3 マップの全要素の出力
    public void showValues(Map map) {
        Collection values = map.values();
        Iterator it = values.iterator();
        while (it.hasNext()) {
            Object obj = it.next();
            System.out.println(obj.toString());
        }
    }

 

コラム HashMapかTreeMapか

MapをインプリメントしたクラスにはHashMap, TreeMap, Hashtable, IdentityHashMap, LinkedHashMap, WeakHashMapの6種類あります。

IdentityHashMap, LinkedHashMap, WeakHashMapクラスは特殊な用途にだけ使用され、通常は使われることはありません。HashtableクラスはVectorと同様にJava 2で使用する意味はほとんどないので、通常使用するのはHashMapクラスとTreeMapクラスになります。

HashMapクラスはキーと要素の対応にハッシュを使用し、TreeMapクラスはをバイナリツリーを使用しています。その特徴をまとめたのが表1です。

表1から明らかですが、パフォーマンス的にはHashMapが優れています。これはTreeMapがツリーを使用しているためで、要素が増えると処理時間が増大するからです。

それでは、TreeMapはどのようなときに使うのでしょうか。TreeMapはMapインタフェース以外にSortedMapインタフェースを実装しています。したがって、SortedMapインタフェースが必要とされている場合に、つまりキーのソートが必要なときにTreeMapを使用するのがいいでしょう。

  要素の取得 要素の登録 要素の削除
HashMap
TreeMap × × ×

 

 

コラム ネーミングサービスとMapインタフェース

ネーミングサービスとは名前と特定のオブジェクトとの対応を行うサービスです。例えば、RMIのNamingクラスはrebind (またはbind)メソッドを使用してrmi://で始まる名前とオブジェクトを対応づけ、lookupメソッドで名前に対応するオブジェクトを検索します。

このネーミングサービスはMapインタフェースを使用することで簡単に実装することができます。例えば、先ほどのNamingクラスを単純化するとリスト4のように記述することができます。これ以外にもネーミングサービス的な使用例は多くあります。

リスト4 単純化したネーミングサービス
    private Map bindings;
 
    public void rebind(String name, Remote obj) {
        bindings.put(name, obj);
    }
 
    public Remote lookup(String name) {
        return (Remote)bindings.get(name);
    }

 

 

(2002.09)