2重のMap

ネストしたMap、つまりMapに格納される値がMapで構成されるMap を扱うのは面倒だったりする。
そこで考えたのが、以下のインターフェースと実装クラスである。
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
/**
 * 2重Map インターフェース.
 * 2重のKeyによるMap、つまり,ネストされたマップ、Map<K,Map<K,V>> を
 * 扱うためのメソッドを約束する。
 * 実装クラスは、DouleHashMap で、new 演算子コンストラクタで生成する。
 */

public interface DoubleMap<K,V>{
   /**
    * 値の格納.
    * @param key1 第1のKey
    * @param key2 第2のKey
    * @param value 格納値
    * @return 古い値が存在すればその値、無ければ NULL が返る。
    */

   public V put(K key1,K key2,V value);

   /**
    * Mapの格納.
    * @param key1 第1のKey
    * @param map Map<K,V>
    * @return 古い Map<K,V>が存在すればそのマップ、無ければ NULL が返る。
    */

   public Map<K,V> put(K key1,Map<K,V> map);

   /**
    * 値の取得.
    * @param key1 第1のKey
    * @param key2 第2のKey
    * @return key1とkey2の組合せが指す値
    */

   public V get(K key1,K key2);

   /**
    * Mapの取得.
    * @param key1 第1のKey
    * @return key1が指すMap
    */

   public Map<K,V> get(K key1);

   /**
    * 第1Key の存在確認
    * @param key1 第1のKey
    * @return true=key1 が存在
    */

   public boolean containsKey(K key1);

   /**
    * 第1Key と第2Key の組合せ、存在確認
    * @param key1 第1のKey
    * @param key2 第2のKey
    * @return true=「第1Key と第2Key の組合せ」が存在する。
    */

   public boolean containsKey(K key1,K key2);

   /**
    * 格納されている値の全個数サイズを返す。
    * @return 全個数サイズ
    */

   public int size();

   /**
    * 第1Key が指すマップサイズを返す。
    * @param key1 第1Key
    * @return key1が指すMapのsize()
    */

   public int size(K key1);

   /**
    * 第1KeyのキーSetを取得
    * @return Set<K>
    */

   public Set<K> keySet();

   /**
    * 第2KeyのキーSetを取得
    * @param key1 第1Key
    * @return key1で取得できるMapのkeyのSet<K>
    */

   public Set<K> keySet(K key1);

   /**
    * Mapコレクション取得
    * @return Collection<Map<K,V>> 第1Keyが指すMapの並び
    */

   public Collection<Map<K,V>> values();

   /**
    * 値コレクション取得
    * @param key1 第1Key
    * @return key1で取得できるMapのvalues()に相当
    */

   public Collection<V> values(K key1);

   /**
    * マップ全体クリア
    */

   public void clear();

   /**
    * 第1Keyが指すマップをクリア
    * @param key1 第1Key
    */

   public void clear(K key1);

   /**
    * マップの離脱
    * @param key1 第1Keyが指すマップを離脱
    * @return 離脱前のMapを取得
    */

   public Map<K,V> remove(K key1);

   /**
    * 値の離脱
    * @param key1 第1Key
    * @param key2 第2Key
    * @return 脱前の値を取得
    */

   public V remove(K key1,K key2);

   /**
    * このマップに含まれるマップの Set ビューを返します。
    * @return et<Entry<K,Map<K,V>>>
    */

   public Set<Entry<K,Map<K,V>>> entrySet();

   /**
    * 指定されたオブジェクトがこのマップと等しいかどうかを比較します。
    * @param o このマップと等しいかどうかを比較するオブジェクト
    * @return 指定されたオブジェクトがマップと等しい場合は true
    */

   public boolean equals(Object o);

   /**
    * マップのハッシュコード値を返します
    * @return マップのハッシュコード値
    */

   public int hashCode();
}
//--------------------------------------------------------------------
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

public class DoubleHashMap<K,V> implements DoubleMap<K,V>{
   private Map<K,Map<K,V>> map;

   public DoubleHashMap(){
      this.map = new HashMap<K,Map<K,V>>();
   }

   @Override
   public V put(K key1,K key2,V value){
      if (!this.map.containsKey(key1)){
         this.map.put(key1,new HashMap<K,V>());
      }
      return this.map.get(key1).put(key2,value);
   }
   @Override
   public Map<K,V> put(K key1,Map<K,V> m){
      return this.map.put(key1,m);
   }
   @Override
   public Map<K,V> get(K key1){
      return this.map.get(key1);
   }
   @Override
   public V get(K key1,K key2){
      return this.map.get(key1).get(key2);
   }
   @Override
   public Set<K> keySet(){
      return this.map.keySet();
   }
   @Override
   public Set<K> keySet(K key1){
      return this.map.containsKey(key1) ? this.map.get(key1).keySet() : new HashSet<K>();
   }
   @Override
   public Collection<Map<K,V>> values(){
      return this.map.values();
   }
   @Override
   public Collection<V> values(K key1){
      return this.map.get(key1).values();
   }
   @Override
   public boolean containsKey(K key1){
      return this.map.containsKey(key1);
   }
   @Override
   public boolean containsKey(K key1,K key2){
      return this.map.containsKey(key1) ? this.map.get(key1).containsKey(key2) : false;
   }
   @Override
   public int size(){
      return this.map.size();
   }
   @Override
   public int size(K key1){
      return this.map.containsKey(key1) ? this.map.get(key1).size() : 0;
   }
   @Override
   public void clear(){
      this.map.clear();
   }
   @Override
   public void clear(K key1){
      this.map.get(key1).clear();
   }
   @Override
   public Map<K,V> remove(K key1){
      return this.map.remove(key1);
   }
   @Override
   public V remove(K key1,K key2){
      return this.map.get(key1).remove(key2);
   }
   @Override
   public Set<Entry<K,Map<K,V>>> entrySet(){
      return this.map.entrySet();
   }
   @SuppressWarnings("unchecked")
   @Override
   public boolean equals(Object o){
      DoubleMap<K,V> m2 = (DoubleMap<K,V>)o;
      return this.map.entrySet().equals(m2.entrySet());
   }
   @Override
   public int hashCode(){
      return this.map.hashCode();
   }
   @Override
   public String toString(){
      StringBuffer sb = new StringBuffer();
      for(Iterator<K> it=this.map.keySet().iterator();it.hasNext();){
         K key1 = it.next();
         sb.append(key1+"={");
         Map<K,V> map2 = this.map.get(key1);
         for(Iterator<K> it2=map2.keySet().iterator();it2.hasNext();){
            K key2 = it2.next();
            sb.append(key2+"="+map2.get(key2));
            if (it2.hasNext()) sb.append(", ");
         }
         sb.append("}");
         if (it.hasNext()) sb.append(", ");
      }
      return "{"+sb.toString()+"}";
   }
}
=================================================
当然、TreeMap や、LinkedHashMap 版も欲しくなる。
DoubleHashMap との差は以下のようになる。
------------------------------------------
public class DoubleTreeMap<K,V> implements DoubleMap<K,V>{
   private Map<K,Map<K,V>> map;
   private Comparator<? super K> cmp2;

   public DoubleTreeMap(){
      this.map = new TreeMap<K,Map<K,V>>();
      this.cmp2 = null;
   }
   public DoubleTreeMap(Comparator<? super K> comparator){
      this.map = new TreeMap<K,Map<K,V>>(comparator);
      this.cmp2 = comparator;
   }
   public DoubleTreeMap(Comparator<? super K> comparator1,Comparator<? super K> comparator2){
      this.map = new TreeMap<K,Map<K,V>>(comparator1);
      this.cmp2 = comparator2;
   }

   @Override
   public V put(K key1,K key2,V value){
      if (!this.map.containsKey(key1)){
         this.map.put(key1,this.cmp2==null ? new TreeMap<K,V>() : new TreeMap<K,V>(this.cmp2));
      }
      return this.map.get(key1).put(key2,value);
   }
 :
-------------------------------------------

public class DoubleLinkedHashMap<K,V> implements DoubleMap<K,V>{
   private Map<K,Map<K,V>> map;
   public DoubleLinkedHashMap(){
      this.map = new LinkedHashMap<K,Map<K,V>>();
   }
   @Override
   public V put(K key1,K key2,V value){
      if (!this.map.containsKey(key1)){
         this.map.put(key1,new LinkedHashMap<K,V>());
      }
      return this.map.get(key1).put(key2,value);
   }
 :