Map インターフェースの完全解説

Map インターフェースの概要

Map インターフェースは、キーと値のペアを管理するための双列コレクションです。Java では、Map インターフェースを実装するクラスとして以下が主に使用されます:

  • HashMap (非スレッドセーフ)
  • HashTable (スレッドセーフ)
  • TreeMap (非スレッドセーフ)
  • LinkedHashMap (スレッドセーフ)
  • ConcurrentHashMap (非スレッドセーフ、Concurrent パッケージ)

HashMap と LinkedHashMap は null キーを許容しますが、TreeMap は null キーを許容しません。HashTable は null キーと null 値を両方とも許容しません。

基本操作 (CRUD)

初期化


HashMap map = new HashMap<>();
HashMap map = new HashMap<>(20, 0.8f); // 初期容量 20、ロードファクター 0.8
        

追加 (Create)


map.put("山田", 25); // 新しいキーを追加
Integer result = map.put("李二郎", 30); // result は null
result = map.put("山田", 26); // result は 25、値が更新される
        

削除 (Delete)


Integer deletedValue = map.remove("李二郎"); // 削除された値が返る
        

更新 (Update)

Map インターフェースは直接の更新メソッドを持ちませんが、put() メソッドを用いて値を上書きすることができます。

取得 (Retrieve)


Integer value = map.get("山田"); // 指定したキーの値を取得
        

常用 API

  • int size() - Map に含まれる要素数を返す
  • boolean isEmpty() - Map が空であるかを判定する
  • boolean containsKey(Object key) - 指定したキーが存在するかを判定する
  • void putAll(Map m) - 別の Map から要素を追加する
  • void clear() - Map を空にする
  • boolean containsValue(Object value) - 指定した値が存在するかを判定する
  • Set keySet() - 全てのキーを Set として返す
  • Collection values() - 全ての値を Collection として返す
  • Set> entrySet() - 全てのキー値ペアを Entry オブジェクトの Set として返す

Map 遍历方法

EntrySet 迭代器


Set> entries = map.entrySet();
Iterator> iterator = entries.iterator();
while(iterator.hasNext()){
    Map.Entry entry = iterator.next();
    System.out.println("キー: " + entry.getKey() + " === 値: " + entry.getValue());
}
        

Lambda 表記


map.forEach((key, value) -> {
    System.out.println("キー: " + key + " === 値: " + value);
});
        

KeySet 増強 for ループ


Set<String> keys = map.keySet();
for (String key : keys) {
    System.out.println("キー: " + key + " === 値: " + map.get(key));
}
        

Stream API

シングルスレッド


map.entrySet().stream().forEach(entry -> {
    System.out.println("キー: " + entry.getKey() + " === 値: " + entry.getValue());
});
        

マルチスレッド


map.entrySet().parallelStream().forEach(entry -> {
    System.out.println("キー: " + entry.getKey() + " === 値: " + entry.getValue());
});
        

高度なトピック (面接、内部実装)

スレッドセーフな Map

  • HashTable - 古い実装、ロック粒度が大きい、非推奨
  • Collections.synchronizedMap - 任意の Map をスレッドセーフに変換、性能が劣る、非推奨
  • ConcurrentHashMap - 分割ロックを用いてロック粒度を小さくし、性能を向上

拡張メカニズム

HashMap は内部配列の容量がいっぱいになると拡張します。拡張は現在の容量の 2 倍にし、全ての要素を再ハッシュします。

  • 初期容量 - 16 がデフォルト
  • ロードファクター - 0.75 がデフォルト
  • 再ハッシュ (Rehashing) - 拡張時に全ての要素のハッシュ値を再計算

JDK 版本の違い

  • JDK 1.7: 配列拡張時に頭から挿入、スレッドUnsafe
  • JDK 1.8: 配列拡張時に尾から挿入、チェーンの長さが8以上になると赤黒木に変換

タグ: HashMap Java コレクション スレッドセーフ

6月14日 00:13 投稿