概要
複合キーのMap
代表的な用途
テーブルから取得したデータリストを任意の複合キーごとに分割したリストに詰め替えたい場合に利用する。
コード
ListUtil
package gr.java_conf.tb.tbpg_util.lang; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * List関連ユーティリティ。 */ public class ListUtil { /** ユーティリティのためコンストラクタを隠蔽 */ private ListUtil() { }; /** * リスト{@code datas}のデータを{@code key}をキーとしたMapに詰め替える。 * * <pre> * 前提1:リストの型{@code T}とMapのキーとなる{@code K}は同一名称のフィールドを持つ。 * 前提2:{@code K}は全てのフィールドをキーとするequals、hashCodeを実装していること。 * </pre> * * @param datas 対象リスト * @param key Mapに指定しるKeyとなるデータクラス * @return リスト{@code datas}のデータを{@code key}をキーとしたMap * @throws SecurityException セキュリティーマネージャー s が存在し、次の条件のどれかが満たされる場合. <br /> * ・s.checkMemberAccess(this, * Member.PUBLIC)の呼び出しがこのフィールドへのアクセスを許可しない<br /> * ・呼び出し側のクラスローダーが同じでないか、現在のクラスローダーの上位クラスローダーと * s.checkPackageAccess()<br /> * の呼び出しがこのクラスのパッケージへのアクセスを許可しない * @throws NoSuchFieldException メソッドが見つからなかった場合 * @throws IllegalAccessException 基本となるフィールドにアクセスできない場合 * @throws IllegalArgumentException 指定されたオブジェクトが基本となるフィールド (またはそのサブクラスか実装側) * を宣言するクラスまたはインタフェースのインスタンスではない場合 * @throws InstantiationException この Class が abstract * クラス、インタフェース、配列クラス、プリミティブ型、または void * を表す場合、クラスが引数なしのコンストラクタを保持しない場合、あるいはインスタンスの生成がほかの理由で失敗した場合 */ public static <K, T> Map<K, List<T>> getMultiKeyMapList(List<T> datas, Class<K> keyClass) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException, InstantiationException { Map<K, List<T>> map = new HashMap<K, List<T>>(); for (T data : datas) { K key = keyClass.newInstance(); for (Field field : keyClass.getDeclaredFields()) { // ※ReflectionUtil部分は自作のユーティリティ。リフレクションでアクセサの操作を行なっています ReflectionUtil.setField(key, field.getName(), ReflectionUtil.getField(data, field.getName())); } if (!map.containsKey(key)) { map.put(key, new ArrayList<T>()); } List<T> list = map.get(key); list.add(data); } return map; } }
ListUtilTest
package gr.java_conf.tb.tbpg_util.lang; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.junit.experimental.runners.Enclosed; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; @RunWith(Enclosed.class) public class ListUtilTest { @RunWith(Theories.class) public static class GetMultiKeyMapList { @SuppressWarnings("unused") private static class Hoge { private String hogeStr; private Integer hogeInt; private Boolean hogeBool; public Hoge() { } public Hoge(String hogeStr, Integer hogeInt, Boolean hogeBool) { super(); this.hogeStr = hogeStr; this.hogeInt = hogeInt; this.hogeBool = hogeBool; } public String getHogeStr() { return hogeStr; } public void setHogeStr(String hogeStr) { this.hogeStr = hogeStr; } public Integer getHogeInt() { return hogeInt; } public void setHogeInt(Integer hogeInt) { this.hogeInt = hogeInt; } public Boolean getHogeBool() { return hogeBool; } public void setHogeBool(Boolean hogeBool) { this.hogeBool = hogeBool; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((hogeBool == null) ? 0 : hogeBool.hashCode()); result = prime * result + ((hogeInt == null) ? 0 : hogeInt.hashCode()); result = prime * result + ((hogeStr == null) ? 0 : hogeStr.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Hoge other = (Hoge) obj; if (hogeBool == null) { if (other.hogeBool != null) return false; } else if (!hogeBool.equals(other.hogeBool)) return false; if (hogeInt == null) { if (other.hogeInt != null) return false; } else if (!hogeInt.equals(other.hogeInt)) return false; if (hogeStr == null) { if (other.hogeStr != null) return false; } else if (!hogeStr.equals(other.hogeStr)) return false; return true; } @Override public String toString() { return "Hoge [hogeStr=" + hogeStr + ", hogeInt=" + hogeInt + ", hogeBool=" + hogeBool + "]"; } } @SuppressWarnings("unused") private static class Hige { private String hogeStr; private Integer hogeInt; private Boolean hogeBool; private String higeStr; private Integer higeInt; private Boolean higeBool; public Hige() { } public Hige(String hogeStr, Integer hogeInt, Boolean hogeBool, String higeStr, Integer higeInt, Boolean higeBool) { super(); this.hogeStr = hogeStr; this.hogeInt = hogeInt; this.hogeBool = hogeBool; this.higeStr = higeStr; this.higeInt = higeInt; this.higeBool = higeBool; } public String getHogeStr() { return hogeStr; } public void setHogeStr(String hogeStr) { this.hogeStr = hogeStr; } public Integer getHogeInt() { return hogeInt; } public void setHogeInt(Integer hogeInt) { this.hogeInt = hogeInt; } public Boolean getHogeBool() { return hogeBool; } public void setHogeBool(Boolean hogeBool) { this.hogeBool = hogeBool; } public String getHigeStr() { return higeStr; } public void setHigeStr(String higeStr) { this.higeStr = higeStr; } public Integer getHigeInt() { return higeInt; } public void setHigeInt(Integer higeInt) { this.higeInt = higeInt; } public Boolean getHigeBool() { return higeBool; } public void setHigeBool(Boolean higeBool) { this.higeBool = higeBool; } } @Theory public void testGetMultiKeyMapList() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InstantiationException { List<Hige> datas = new ArrayList<Hige>(); Hige hige1 = new Hige("hoge", Integer.valueOf(10), Boolean.valueOf(true), "hige1", Integer.valueOf(10), Boolean.valueOf(true)); datas.add(hige1); Hige hige2 = new Hige("hoge", Integer.valueOf(10), Boolean.valueOf(true), "hige2", Integer.valueOf(20), Boolean.valueOf(false)); datas.add(hige2); Hige hige3 = new Hige("hoge", Integer.valueOf(30), Boolean.valueOf(true), "hige3", Integer.valueOf(30), Boolean.valueOf(true)); datas.add(hige3); Hoge hoge1 = new Hoge("hoge", Integer.valueOf(10), Boolean.valueOf(true)); Map<Hoge, List<Hige>> multiKeyMap = ListUtil.getMultiKeyMapList(datas, Hoge.class); List<Hige> actual1 = multiKeyMap.get(hoge1); assertThat(actual1.size(), is(Integer.valueOf(2))); for (Entry<Hoge, List<Hige>> entry : multiKeyMap.entrySet()) { System.out.print(entry.getKey()); System.out.println(entry.getValue()); } } } }
出力内容
Hoge [hogeStr=hoge, hogeInt=10, hogeBool=true][Hige [hogeStr=hoge, hogeInt=10, hogeBool=true, higeStr=hige1, higeInt=10, higeBool=true], Hige [hogeStr=hoge, hogeInt=10, hogeBool=true, higeStr=hige2, higeInt=20, higeBool=false]] Hoge [hogeStr=hoge, hogeInt=30, hogeBool=true][Hige [hogeStr=hoge, hogeInt=30, hogeBool=true, higeStr=hige3, higeInt=30, higeBool=true]]