JavaのHashMapとは?仕組み・使い方・注意点をわかりやすく解説
CONTENTS
Javaで「キーから値を引く」処理を作るなら、HashMapは定番です。しかし、仕組みを知らないまま使うと、取得できない不具合や性能劣化が起きます。
そこで本記事では、HashMapの基本から内部構造、実務での落とし穴までを整理します。そのため、読み終えるころには「いつ使い、何に注意するか」が判断できます。
なお、Map全体の位置づけを先に押さえたい方は、内部リンクの関連記事も参考にしてください。
HashMapとは何か
まず、HashMapは「キー」と「値」を1対1で管理するクラスです。そのため、キーを指定して値を高速に取り出せます。
一方で、要素の並び順は保証されません。したがって、順序が必要な画面表示や帳票では不向きです。
さらに、HashMapはnullキーを1つだけ許容します。また、null値は複数入れられます。ただし、意図しないnullはバグになりがちです。
HashMapが向いている場面
例えば、「ユーザーIDからユーザー情報を取得する」「設定名から設定値を引く」などが典型です。つまり、検索キーがはっきりしている場面で強いです。
HashMapの基本的な使い方
次に、基本操作を確認します。結論として、覚えるのはputとgetが中心です。
Map<String, Integer> map = new HashMap<>();
map.put("apple", 100);
map.put("banana", 150);
int price = map.get("apple");
しかし、getで返るのは「存在しないときはnull」です。したがって、プリミティブ型に代入すると例外の原因になります。
そのため、存在チェックやデフォルト値の指定が重要です。
存在チェックのコツ
まず、キーの存在はcontainsKeyで確認します。一方で、containsValueは全件走査になりやすいです。したがって、頻繁に使う設計は避けましょう。
例えば、デフォルト値が欲しいならgetOrDefaultが便利です。つまり、null判定を減らせます。
HashMapの内部構造と「速い理由」
さらに、なぜ速いのかを理解します。HashMapは内部に配列(バケット)を持ちます。そして、キーのハッシュ値から格納位置を決めます。
そのため、理想的には「1回の計算」で目的の場所に到達します。つまり、検索が速いわけです。
しかし、異なるキーでも同じ位置になることがあります。これがハッシュ衝突です。衝突が増えると、探索回数が増えて遅くなります。
一方で、Java 8以降は条件により木構造(赤黒木)へ変換されます。したがって、最悪ケースの劣化を抑えられます。
ハッシュ衝突が増える原因
例えば、hashCodeが偏っていると衝突が増えます。また、キー設計が雑でも偏りが出ます。したがって、キー設計は性能に直結します。
equalsとhashCodeが重要な理由
次に、実務で最も事故りやすいポイントです。HashMapは、キーの一致判定にequalsを使います。そして、格納位置の計算にhashCodeを使います。
そのため、両方が整合していないと取得できません。つまり、「入れたのに取れない」状態になります。
例えば、equalsが同じならhashCodeも同じである必要があります。したがって、キーに独自クラスを使うなら、このルールを守りましょう。
なお、equals/hashCodeの実装方針は別記事にまとめると管理しやすいです。必要なら内部リンク先を用意してください。
実務でよくある注意点
ここからは実務目線で整理します。まず、可変オブジェクトをキーにするのは避けましょう。なぜなら、状態変化でhashCodeが変わるからです。
その結果、同じキーでgetしても見つからなくなります。したがって、キーは不変にするのが安全です。
さらに、順序が必要なのにHashMapを選ぶミスも多いです。その場合はLinkedHashMapを検討します。つまり、用途で実装を変えるべきです。
一方で、ソートが必要ならTreeMapが候補です。ただし、比較コストが乗る点は理解しましょう。
また、HashMapはスレッドセーフではありません。したがって、並行処理ではConcurrentHashMapを検討してください。
どのMapを選ぶべきか
最後に選び方をまとめます。結論として、迷ったら要件を3点で切り分けます。
- 順序が必要か
- ソートが必要か
- 並行処理があるか
例えば、順序が不要で単純に速く引きたいならHashMapです。一方で、挿入順を保つならLinkedHashMapです。さらに、常にソートされた状態が必要ならTreeMapです。
まとめ
HashMapは、キーから値を高速に取得できる便利な仕組みです。しかし、順序保証がない点、nullの扱い、equals/hashCode、衝突と性能には注意が必要です。
そのため、内部構造とキー設計を押さえるだけで、トラブルは大きく減ります。まずは自分のコードで「キーが不変か」「nullが混ざらないか」を点検してみてください。
つまずいたら、現役エンジニアと一緒に解決しよう
この記事で扱った【Java】は、独学だと細部で詰まりやすい分野です。さらに理解を深めたい方は、Zerocodeで実務直結の学習を進めてみませんか。
コード添削・詰まり解消を丁寧にサポート。
Java/SQL/Spring Bootを体系的に習得。
現場で刺さる成果物づくりを伴走。
時間と場所を選ばず学べます。