Java 逆引き集 | Collections.newSetFromMap(Map を Set に変換) — カスタム Set 実装

Java Java
スポンサーリンク

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 ではできないカスタム集合を簡単に構築できる。
タイトルとURLをコピーしました