LinkedHashMap をざっくりイメージする
まず、すごくラフに言うと
「順番を覚えてくれる HashMap」
が LinkedHashMap です。
HashMap は「キー → 値」を高速に扱える代わりに、順番は一切保証しませんでした。LinkedHashMap は
- Map(キー → 値)の使い勝手はそのまま
- さらに「どの順番で扱うか」をちゃんと覚えてくれる
というクラスです。
コードではだいたいこう書きます。
import java.util.LinkedHashMap;
import java.util.Map;
Map<String, Integer> map = new LinkedHashMap<>();
Java左を Map、右を LinkedHashMap にするのは、他の Map と同じ“お約束”です。
HashMap との違いを直感でつかむ(ここは超重要)
HashMap は順番がぐちゃぐちゃ、LinkedHashMap は「順番を保つ」
まず、HashMap の挙動を見ておきます。
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 1);
hashMap.put("banana", 2);
hashMap.put("orange", 3);
System.out.println(hashMap); // {orange=3, apple=1, banana=2} など、順番バラバラ
Java入れた順番どおりに出てくるとは限りません。
ここに期待してはいけません。
同じことを LinkedHashMap でやるとどうなるか。
import java.util.LinkedHashMap;
import java.util.Map;
Map<String, Integer> linked = new LinkedHashMap<>();
linked.put("apple", 1);
linked.put("banana", 2);
linked.put("orange", 3);
System.out.println(linked); // {apple=1, banana=2, orange=3}
Java入れた順番(挿入順)どおりに保たれます。
つまり、
- HashMap → 「順番は未定義。バラバラ」
- LinkedHashMap → 「挿入順を記憶してくれる」
という違いです。
「画面に表示するとき、登録した順番どおりに並べたい」のような場面では、
HashMap ではなく LinkedHashMap を選ぶべきです。
基本操作(put / get / remove)はほぼ HashMap と同じ
put / get / remove の挙動
基本的な使い方は HashMap とまったく同じです。
Map<String, String> users = new LinkedHashMap<>();
users.put("u001", "山田");
users.put("u002", "佐藤");
users.put("u003", "鈴木");
System.out.println(users.get("u002")); // 佐藤
users.remove("u001");
System.out.println(users); // {u002=佐藤, u003=鈴木}
Javaキーは一意で、同じキーに put すると上書きされる。
値は重複していてもよい。
get で取り出し、remove で削除、containsKey で存在チェック。
これらはすべて HashMap と同じです。
ループしたときに「順番が保たれる」という違い
優位性が出てくるのは、Map をループする場面です。
for (Map.Entry<String, String> e : users.entrySet()) {
System.out.println(e.getKey() + " → " + e.getValue());
}
JavaLinkedHashMap なら、ここでの順番が「挿入した順番」になります。
HashMap だとバラバラです。
画面表示、ログ出力、ファイル保存など、「人間が見る順番」が意味を持つ場合、
ここがかなり効いてきます。
LinkedHashMap が「順番を覚えられる」仕組みのざっくりイメージ
内部的には、
- HashMap のようにハッシュテーブルを持ちつつ
- さらに「前後の要素へのリンク(双方向リスト)」も持っている
という構造になっています。
ざっくり言えば、HashMap に「順番用の LinkedList 機能」がくっついているイメージです。
この“鎖”のおかげで
- どの要素が最初に追加されたか
- 次はどれか
- 最後はどれか
といった情報を簡単に辿れるようになっています。
その代わり、HashMap よりメモリを多く使い、
少しだけ重い(オーバーヘッドがある)とも言えます。
だから「順番が欲しいときだけ LinkedHashMap」を選ぶのが、設計として自然です。
「アクセス順」にも並べられるという裏機能(LRU もどきの基礎)
ここから少し踏み込んだ話です。
LinkedHashMap には、もう一つ重要なモードがあります。
コンストラクタで
new LinkedHashMap<>(初期容量, 負荷係数, accessOrder)
Javaという形を使うと、「順番の意味」を切り替えられます。
挿入順モード(デフォルト)
accessOrder を false(または指定なし)にすると、
今まで説明してきた「挿入順」が保たれます。
LinkedHashMap<String, Integer> map =
new LinkedHashMap<>(16, 0.75f, false); // これが普通
Javaアクセス順モード(accessOrder = true)
accessOrder を true にすると、「アクセスされた順」に並び替えられるようになります。
LinkedHashMap<String, Integer> map =
new LinkedHashMap<>(16, 0.75f, true);
Javaこのモードでは、get(や put)でアクセスされるたびに、
そのエントリが「一番新しい位置(末尾)」に移動します。
簡単な例で見てみましょう。
LinkedHashMap<String, Integer> map =
new LinkedHashMap<>(16, 0.75f, true);
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
System.out.println(map); // {A=1, B=2, C=3} (挿入順)
map.get("A"); // A にアクセス
System.out.println(map); // {B=2, C=3, A=1} (A が最後に移動)
Javaこの機能を使うと、
「最近使ったもの」と「長いこと使っていないもの」を順番で表現できます。
いわゆる「LRU キャッシュ」の土台としてよく使われます。
LRU キャッシュ風の使い方をイメージしてみる(少し応用)
「最大 N 個まで覚えておき、溢れたら一番古いものから消す」というキャッシュを考えます。
LinkedHashMap は removeEldestEntry というメソッドをオーバーライドすることで、
「いつ一番古い要素を自動削除するか」を制御できます。
import java.util.LinkedHashMap;
import java.util.Map;
public class LruCache<K, V> extends LinkedHashMap<K, V> {
private final int maxSize;
public LruCache(int maxSize) {
super(16, 0.75f, true); // accessOrder = true でアクセス順モード
this.maxSize = maxSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maxSize; // サイズが超えたら一番古いエントリを削除
}
}
Java使い方は普通の Map と同じです。
LruCache<String, String> cache = new LruCache<>(3);
cache.put("A", "a");
cache.put("B", "b");
cache.put("C", "c");
cache.get("A"); // A を最近使ったことになる
cache.put("D", "d"); // このタイミングで一番古い「B」が消されるイメージ
Java初心者の段階でここまで実装できなくてもかまいません。
大事なのは
「LinkedHashMap は、挿入順だけでなく“アクセス順”も扱える。
これを使うとキャッシュのようなものも作れる」
という感覚です。
LinkedHashMap を選ぶべき場面と、選ばなくていい場面
LinkedHashMap を選ぶべき場面
次のような条件が揃うとき、LinkedHashMap が向いています。
- Map(キー → 値)で管理したい
- でも「順番」も意味がある
- 追加した順に表示したい
- CSV や JSON として出力するときの順番を固定したい
- 最近使った順に処理したい(アクセス順モード)
例えば、
- 「最初に登録した商品から順に一覧表示したい商品マスタ」
- 「設定項目を定義順にファイル保存したい設定 Map」
- 「アクセス回数に応じて古いものを捨てる簡易キャッシュ」
こういうのは、HashMap より LinkedHashMap のほうが自然です。
HashMap で十分な場面
逆に、次のようなときは HashMap のままで構いません。
- 順番は本当にどうでもいい(どの順に出てきても困らない)
- ひたすら「キーで速く取れればいい」だけの用途
- 表示時には、どうせ別途ソートする
順番に意味が無いのに LinkedHashMap を使うと、
「順番管理のオーバーヘッド」を払い損ねることになります。
順番が必要かどうか、ちゃんと自分に問いかけてから選ぶと、
設計が一段クリアになります。
まとめ:LinkedHashMap を頭の中でこう位置づける
初心者向けに、LinkedHashMap の本質をまとめるとこうです。
- Map(キー → 値)としての基本は HashMap と同じ。
- 追加した順番(挿入順)をそのまま覚えてくれる。
- 特殊モード(accessOrder = true)では「アクセスされた順」に並べ替えてくれる。
- そのために、ハッシュテーブル+「順番用のリンク構造」を内部に持っている。
- 「順番まで含めて意味のある Map」が欲しいときに選ぶべきクラス。
