導入
Java開発において、Mapインターフェースは最も頻繁に使用されるコレクションの一つです。しかし、要件に適さないMap実装を選択すると、メモリリークや意図しないソート順、あるいはパフォーマンス低下を招くことがあります。本記事では、主要な5つのMap実装を整理し、現場で迷わないための使い分けの基準を解説します。
基礎知識
Mapはキーと値のペアを保持するデータ構造です。Javaではjava.util.Mapインターフェースを実装するクラス群が提供されています。
HashMapはハッシュテーブルを用いた汎用的なMapですが、順序は保証されません。TreeMapはキーを自然順序またはComparatorでソートします。LinkedHashMapは挿入順序を保持します。WeakHashMapはキーが弱参照であるため、GC(ガベージコレクション)の対象になりやすく、キャッシュ用途に向いています。IdentityHashMapはequals()メソッドではなく「==」で等価性を判定する特殊なMapです。
実装/解決策
開発現場での選定基準は以下の通りです。
1. 基本は HashMap を使用する。
2. 順序が重要なら LinkedHashMap(挿入順)または TreeMap(ソート順)。
3. メモリ管理を意識した一時キャッシュなら WeakHashMap。
4. インスタンスの同一性(メモリ上の場所)をキーにしたい場合は IdentityHashMap。
サンプルプログラム
以下のコードでは、代表的なMap実装の特性を確認できます。
import java.util.;
public class MapExample {
public static void main(String[] args) {
// 1. HashMap: 順序はバラバラだが検索は高速
Map
hashMap.put("B", "Orange");
hashMap.put("A", "Apple");
System.out.println("HashMap: " + hashMap);
// 2. TreeMap: キーがソートされる
Map
treeMap.put("B", "Orange");
treeMap.put("A", "Apple");
System.out.println("TreeMap: " + treeMap); // A, Bの順になる
// 3. LinkedHashMap: 挿入した順序を維持する
Map
linkedMap.put("B", "Orange");
linkedMap.put("A", "Apple");
System.out.println("LinkedHashMap: " + linkedMap); // B, Aの順になる
// 4. IdentityHashMap: 等価性ではなくメモリ上の同一性で比較
Map
String key1 = new String("key");
String key2 = new String("key");
identityMap.put(key1, "Value1");
identityMap.put(key2, "Value2");
// キーの内容は同じだが、別のインスタンスなので別々のエントリとして格納される
System.out.println("IdentityHashMap size: " + identityMap.size()); // 2が出力される
}
}
応用・注意点
現場で最も陥りやすい罠は、スレッドセーフではないという点です。マルチスレッド環境でMapを共有する場合は、Collections.synchronizedMap()でラップするか、ConcurrentHashMapを使用してください。
また、IdentityHashMapはHashMapとは全く異なるアルゴリズム(線形プローブ法)で実装されているため、Mapインターフェースの一般的な契約(equalsメソッドを利用する前提)に違反している点に注意してください。あくまで「特定のインスタンスの参照を追跡したい」といった特殊なケースでのみ使用するのが賢明です。最後に、Java 21以降で導入された Sequenced Collections(LinkedHashMapなどが実装)を活用すると、先頭や末尾へのアクセスが容易になりますので、最新仕様も併せて確認することをお勧めします。

コメント