Collections.newSetFromMap(Map を Set に変換) — カスタム Set 実装
Java には Collections.newSetFromMap(Map<E,Boolean>) というユーティリティがあり、任意の Map を基盤にした Set を作れます。これを使うと「特殊な Map 実装をベースにした Set」を簡単に構築できるので、カスタム用途(例えば IdentityHashMap を使った参照同一性 Set、WeakHashMap を使った弱参照 Set)に役立ちます。
基本の仕組み
- 通常の Set 実装:
HashSetは内部的にHashMapを使っている。 - newSetFromMap: 任意の
Map<E,Boolean>を渡すと、その Map を裏で使う Set を返す。 - 制約: 渡す Map は空である必要がある(既存要素があると例外)。
- 用途: Map の特性をそのまま Set に転用できる。
基本コード例
IdentityHashMap を基盤にした「参照同一性 Set」
import java.util.*;
public class IdentitySetDemo {
public static void main(String[] args) {
Set<String> idSet = Collections.newSetFromMap(new IdentityHashMap<>());
String a1 = new String("hello");
String a2 = new String("hello");
idSet.add(a1);
idSet.add(a2);
System.out.println(idSet.size()); // 2 (equalsではなく==で判定)
}
}
Java- ポイント: 通常の HashSet なら equals で同値判定し 1 件になるが、IdentityHashMap を基盤にすると「参照同一性」で区別される。
WeakHashMap を基盤にした「弱参照 Set」
import java.util.*;
public class WeakSetDemo {
public static void main(String[] args) {
Set<Object> weakSet = Collections.newSetFromMap(new WeakHashMap<>());
Object o = new Object();
weakSet.add(o);
System.out.println(weakSet.contains(o)); // true
o = null;
System.gc(); // GC後に弱参照が消える可能性あり
// 時間経過後には要素が消えることもある
}
}
Java- ポイント: GC が走ると要素が消える「弱参照 Set」を簡単に作れる。
例題で理解する
例題1: 参照同一性で重複を許さないキャッシュ
Set<Object> cache = Collections.newSetFromMap(new IdentityHashMap<>());
Object x1 = new String("data");
Object x2 = new String("data");
cache.add(x1);
cache.add(x2);
System.out.println(cache.size()); // 2(参照が違うので両方保持)
Java- 用途: 同じ内容でも別インスタンスを区別したいとき。
例題2: 弱参照で「自動消滅するタグ集合」
Set<String> tags = Collections.newSetFromMap(new WeakHashMap<>());
tags.add(new String("temp"));
System.out.println(tags.size()); // 1
System.gc();
// GC後に消える可能性 → 一時的なメモリ管理に便利
Java- 用途: メモリに残っている間だけ存在する「弱い集合」。
例題3: LinkedHashMap を基盤にした「順序保持 Set」
Set<String> ordered = Collections.newSetFromMap(new LinkedHashMap<>());
ordered.add("A");
ordered.add("B");
ordered.add("C");
System.out.println(ordered); // [A, B, C] 順序保持
Java- 用途: 順序を保持した Set を簡単に作れる。
テンプレート集
- IdentityHashMap ベース
Set<T> s = Collections.newSetFromMap(new IdentityHashMap<>());
Java- WeakHashMap ベース
Set<T> s = Collections.newSetFromMap(new WeakHashMap<>());
Java- LinkedHashMap ベース(順序保持)
Set<T> s = Collections.newSetFromMap(new LinkedHashMap<>());
Java- ConcurrentHashMap ベース(並行 Set)
Set<T> s = Collections.newSetFromMap(new ConcurrentHashMap<>());
Java落とし穴と回避策
- 渡す Map は空である必要: 既に要素があると IllegalArgumentException。
- equals/hashCode の違い: IdentityHashMap ベースは == 判定。通常の Set と挙動が違うので注意。
- 弱参照の消滅タイミング: WeakHashMap ベースは GC に依存。contains が突然 false になることもある。
- 並行用途: ConcurrentHashMap ベースで作ればスレッドセーフになるが、null キー/値は不可。
- 順序保持: LinkedHashMap ベースで順序を保証できるが、通常の LinkedHashSet で十分な場合もある。
まとめ
Collections.newSetFromMapは「Map の特性をそのまま Set に転用」できる便利ユーティリティ。- IdentityHashMap → 参照同一性 Set、WeakHashMap → 弱参照 Set、LinkedHashMap → 順序保持 Set、ConcurrentHashMap → 並行 Set。
- 渡す Map は空である必要があり、挙動は基盤 Map に依存する。
- 特殊な要件(参照同一性、弱参照、並行性、順序保持)に応じて選ぶと、標準 Set ではできないカスタム集合を簡単に構築できる。
