結論

概念役割
Mapキー(key)と値(value)の組 を格納するコレクション
キーの重複不可(同じキーに put すると値が上書きされる)
アクセス方法キー指定 で値を取得(Listのインデックスアクセスとの違い)
主な実装クラスHashMap(ハッシュテーブルベース、検索が速い)

「IDから名前を引く」「英単語から意味を引く」のような 対応表 を扱いたいときに使う。

サンプルコード

Map インターフェースと HashMap 実装クラスをimportして使う。

import java.util.HashMap; // Mapの実装クラスであるHashMapをインポート
import java.util.Map;     // Mapインターフェースをインポート

public class Main {

    public static void main(String[] args) {
        // HashMapのインスタンスを生成し、Map型の変数colorMapに代入
        // (キーの型:String、値の型:String)
        Map<String, String> colorMap = new HashMap<>();

        // マップにデータを登録する
        colorMap.put("red", "赤");
        colorMap.put("blue", "青");
        colorMap.put("yellow", "黄");
        colorMap.put("green", "緑");

        // キー指定して値を取得
        System.out.println(colorMap.get("red"));
        System.out.println(colorMap.get("blue"));

        // キー指定して上書きする
        colorMap.put("red", "赤色");
        System.out.println(colorMap.get("red"));

        // "yellow" キーのペアを削除
        colorMap.remove("yellow");
        // マップの要素数を表示(3が表示される)
        System.out.println(colorMap.size());
    }
}

実行結果:



赤色
3

ポイント:

  • put は登録と上書きを兼ねる: 同じキーに2回 put すると、後から入れた値で上書きされる
  • get で存在しないキーを引くと nullNullPointerException を避けたいなら getOrDefault(key, defaultValue) も使える
  • キーの重複は許されないが、値の重複は許される(複数のキーが同じ値を指してOK)

代表メソッド

メソッド概要戻り値
put(K key, V value)キーと値の組をマップに追加。同じキーが既に存在する場合は値を上書きV(上書き前の値、存在しなかった場合は null
get(Object key)指定キーに対応する値を返す。キーが存在しない場合は nullV(値の型)
remove(Object key)指定キーのキー・値ペアを削除V(削除した値)
size()マップ内のキー・値ペアの数を返すint

put の戻り値が「上書き前の値」になっている点は意外と便利で、「初回登録か上書きか」を見分けるのに使える(戻り値が null なら新規登録)。

全要素を反復する — keySet() で取り出す

特定のキーで get() するだけでなく、Mapに入っている 全てのキー・値ペアを順に処理したい 場面がある。Mapのメリットを活かすなら、keySet() で「Map自身に持っているキー一覧を聞く」のが定石。

import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        Map<Integer, String> greetByTime = new HashMap<>();
        greetByTime.put(9, "おはようございます");
        greetByTime.put(12, "こんにちは");
        greetByTime.put(18, "こんばんは");
        greetByTime.put(22, "おやすみなさい");

        for (int time : greetByTime.keySet()) {
            System.out.println(time + "時:" + greetByTime.get(time));
        }
    }
}

keySet() はMapに登録されている キーの集合(Set<K> を返す。拡張for文で回せば、登録キーの数だけ処理できる。キーが 9, 12, 18, 22 の4つなら4回ループ、100, 200, 300 の3つなら3回ループする。

「キーが何個あるか・何の値かを事前に知らなくても処理できる」のがMapらしい書き方。

HashMap は挿入順を保証しない

上記コードの実行結果は、put した順とは違う 意外な順序 になる。

18時:こんばんは
22時:おやすみなさい
9時:おはようございます
12時:こんにちは

put9 → 12 → 18 → 22 の順だったが、出力は 18 → 22 → 9 → 12。これは HashMapハッシュ計算でバケット位置を決める ため。

Integer.hashCode() は値そのままを返し、デフォルト容量16の HashMap ではバケット位置が key & 15(下位4bit)で決まる。

キーバケット位置(key & 15
99
1212
182
226

→ バケット番号順(2 → 6 → 9 → 12)に取り出されるため、18, 22, 9, 12 の順 で出力される。JDKバージョンや初期容量で具体的な順は変わるが、いずれにせよ「挿入順を保証しない」のは確定仕様。

順序を保証したい場合は、Map実装クラスの差し替えで対応できる。

実装クラス順序の保証
HashMapなし
LinkedHashMap挿入順
TreeMapキー昇順

差し替えは1行で済む(new HashMap<>()new LinkedHashMap<>() に変えるだけ)。実装クラスの選び方は JavaのMap実装クラスの選び方 — HashMap/LinkedHashMap/TreeMap で深掘りしている。

よくある罠 — Listの感覚で get(i) を呼ぶ

Listを覚えた直後にMapを触ると、つい以下のように書いてしまいがち。

// 動かない誤りパターン
Map<Integer, String> greetByTime = new HashMap<>();
greetByTime.put(9, "おはようございます");
greetByTime.put(12, "こんにちは");
greetByTime.put(18, "こんばんは");
greetByTime.put(22, "おやすみなさい");

for (int i = 0; i < greetByTime.size(); i++) {
    System.out.println(i + "時:" + greetByTime.get(i));
}

このコードの出力は 全て null

0時:null
1時:null
2時:null
3時:null

理由:

  • greetByTime.get(0)「キー 0 に対応する値」を探しに行く
  • 登録されているキーは 9, 12, 18, 22 で、0, 1, 2, 3 は存在しない
  • 存在しないキーへの getnull を返す(仕様)

Listはインデックス(0から自動採番される連番)でアクセス、Mapはキー(自分で決めた値)でアクセス という根本的な違いを混同するとハマる。

ListMap
アクセス方法インデックス(自動採番)キー(任意の値)
get(0) の意味先頭の要素キー 0 に対応する値
size() の意味要素数キー・値ペアの数

Mapは キー集合を keySet() で取得して回す か、事前に分かっているキーで直接 get(key) する のが正しい使い方。

型パラメータの制約 — 2つの型を指定する

Map<キーの型, 値の型> という形で 2つの型パラメータ を指定する。Listと同じく 参照型のみ で、基本型はラッパークラスを使う。

Map<String, String> m1  = new HashMap<>();   // キー: 文字列、値: 文字列
Map<Integer, String> m2 = new HashMap<>();   // キー: 数値、値: 文字列
Map<String, List<Integer>> m3 = new HashMap<>(); // キー: 文字列、値: 整数のList

キーと値で 異なる型 を指定できる。値側にコレクションをネストさせるパターン(Map<String, List<...>>)も実務でよく使う。

HashMap固有の特徴 — null キーが使える

HashMapキーに null を指定できるnull キーを1つだけ持てる)。

Map<String, String> m = new HashMap<>();
m.put(null, "no-key");
System.out.println(m.get(null)); // "no-key"

ただし HashtableConcurrentHashMap など他のMap実装ではキーに null 不可。実装クラスを切り替えるときに踏みやすい違いなので注意。

まとめ

  • Mapは「キー → 値」の対応を扱うコレクション
  • キーは重複不可・値は重複可・アクセスはキー経由
  • 全要素を反復するなら keySet() で「Map自身にキー一覧を聞く」
  • HashMap挿入順を保証しない(バケット位置は key & (容量-1) で決まる)。順序が要件なら LinkedHashMap/TreeMap に差し替える
  • Listの感覚で get(0), get(1), ... と書くと全て null になる罠に注意
  • 型パラメータは2つ、Map<K, V> の形で指定する。基本型はラッパークラスで代替

関連記事:

変更履歴

  • 2026-05-05: 初版公開
  • 2026-05-05: 「keySet() で全要素を反復」「HashMapは挿入順を保証しない」「Listの感覚で get(i) を呼ぶ罠」の3節を追加