Map はキーと値のペアを格納する
HashMap(java.util 由来)は対応関係を格納します。各キーは 1 つの値にマッピングされ、キーを使ってほぼ一定時間で値を検索できます。辞書を思い浮かべてください。単語がキーで、定義が値です。
2 つの型パラメータは <KeyType, ValueType> です。ここではキーが String、値が Integer です。ArrayList と同様に、通常は変数を Map インターフェース型として宣言し、HashMap を生成します。
put、get、上書き
身につけておくべき 2 点:
- キーは一意です。既存のキーで
putすると、その値が置き換えられ、古い値が返されます。 - 存在しないキーで
getすると、エラーではなくnullが返されます。そのnullをintに自動アンボックスするとNullPointerExceptionがスローされ、よくあるバグの原因になります。
getOrDefault は null の罠を避ける
毎回 null をチェックする代わりに、デフォルト値を求めましょう:
これは「存在するかもしれない」検索を扱う最もすっきりした方法であり、最も有名な HashMap のパターンへ直接つながります。
出現回数を数える
各要素が何回現れるかを数えるのは、HashMap の教科書的な用途です:
map.put(key, map.getOrDefault(key, 0) + 1) というパターンは「現在のカウント(またはゼロ)を取り、1 を足して、書き戻す」と読めます。よりすっきりした等価表現は counts.merge(word, 1, Integer::sum) です。
確認と削除
putIfAbsent(key, value) はキーが存在しないときだけ書き込みます。遅延初期化に便利です。
HashMap をループする
最もよく使うループは entrySet() をたどり、各キーと値をまとめて取得します:
キーだけ、または値だけが必要な場合:
ラムダを使って forEach を使うこともできます: ages.forEach((name, age) -> System.out.println(name + ": " + age));。
HashMap は順序を保持しない
HashMap は反復処理の順序について何も保証しません。順序はハッシュ化の結果であり、実行ごとに変わることがあります。予測可能な順序が必要な場合:
LinkedHashMapは挿入順を保持します。TreeMapはキーを自然順序(または指定したComparator)でソートして保持します。
3 つとも Map インターフェースを実装しているので、切り替えはコンストラクタの 1 行を変えるだけです。
キーはハッシュ可能でなければならない
HashMap はキーをハッシュ化してエントリを見つけるため、キーの hashCode() と equals() は整合している必要があります。String や Integer などの組み込み型はすでに正しく実装されています。独自のクラスをキーに使う場合は、equals と hashCode の両方をオーバーライドしてください。そうしないと、意味的に「等しい」2 つのオブジェクトが別々のバケットに入り、検索が原因不明の失敗を起こします。
次へ: HashSet
HashMap は「このキーの下に格納されている値は何か?」に答えます。何かが存在するかどうかだけを気にする場合(関連データを持たない、一意な値の集合)に使うツールが HashSet で、これが次のテーマです。
よくある質問
Java で HashMap を作成するには?
2 つの型パラメータ(キーの型と値の型)を指定して宣言し、コンストラクタを呼び出します: Map<String, Integer> ages = new HashMap<>();。次に ages.put("Ada", 36); でエントリを追加し、ages.get("Ada"); で読み取ります。java.util.HashMap と java.util.Map をインポートしてください。
Java で HashMap をループ処理するには?
for-each ループで map.entrySet() を反復処理すると、各キーと値をまとめて取得できます: for (Map.Entry<String, Integer> e : map.entrySet()) { ... }。そして e.getKey() と e.getValue() を読み取ります。キーだけが必要なら map.keySet()、値だけが必要なら map.values() をループすることもできます。HashMap は挿入順を保持しない点に注意してください。
get と getOrDefault の違いは?
get(key) はキーに対応する値を返しますが、キーが存在しない場合は null を返すため、結果をそのまま使うと NullPointerException につながる可能性があります。getOrDefault(key, fallback) は値があればそれを返し、なければ渡したデフォルト値を返すので、null チェックを省けます。特にカウント処理で便利です: counts.put(c, counts.getOrDefault(c, 0) + 1)。