HashMapとは
- Mapインタフェースの実装クラス
- キーと値のペアを格納できる
- Mapの順序は保証されない(追加順にはならない)
- 平均的に高速(O(1)でアクセス可能)
宣言する
import java.util.HashMap;
import java.util.Map;
public class Example {
public static void main(String[] args){
Map<キーの型, 値の型> オブジェクト名 = new HashMap<>();
}
}
基本操作
値を追加する(putメソッド)
Map<Integer, String> hashmap = new HashMap<>();
hashmap.put(1, "りんご");
hashmap.put(4, "パイン");
hashmap.put(2, "オレンジ");
指定キーの値を取得する(getメソッド)
String value = hashmap.get(1); // "りんご"
指定キーの値を取り出す(ない場合は指定値を返す)(getOrDefaultメソッド)
String value = hashmap.getOrDefault(3, "未登録");
要素数を取得する(sizeメソッド)
int size = hashmap.size();
要素の削除(removeメソッド)
hashmap.remove(1); // キー1を削除
存在確認
キーの存在確認(containsKeyメソッド)
if(hashmap.containsKey(1)){
System.out.println("キー1は存在する");
}
値の存在確認(containsValueメソッド)
if(hashmap.containsValue("りんご")){
System.out.println("りんごは存在する");
}
全要素の取得
キーを全て取得する(keySetメソッド)
for(Integer key : hashmap.keySet()){
System.out.println(key);
}
値を全て取得する(valuesメソッド)
for(String value : hashmap.values()){
System.out.println(value);
}
キーと値のペア(Map.Entry)を取得(entrySetメソッド)
System.out.println(hashmap.entrySet());
// [1=りんご, 4=パイン, 2=オレンジ]
Map.Entryとは
- Mapインタフェース内で定義されたインタフェース
- キーと値を1つのオブジェクトとして持つ
主なメソッド
entry.getKey(); // キー取得
entry.getValue(); // 値取得
entrySetの実用
for(Map.Entry<Integer, String> entry : hashmap.entrySet()){
System.out.println(entry.getKey() + " : " + entry.getValue());
}
拡張for文を使って、hashmapの各要素(キーと値のペア)を
Map.Entry型として1つずつ取り出し、entry変数に代入して処理する
forEachメソッドで全要素を処理
基本構文
map.forEach((key, value) -> {
処理;
});
例
map.forEach((key, value) -> {
System.out.println(key + " : " + value);
});
押さえたいポイント
1. キーは重複できない
hashmap.put(1, "りんご");
hashmap.put(1, "みかん"); // 上書きされる
2. nullも扱える
hashmap.put(null, "値"); // キーにnull(1つだけ)
hashmap.put(3, null); // 値にnull
3. 順序が必要なら別クラス
- 順序保持 → LinkedHashMap
- ソート順 → TreeMap
4. Mapで宣言する理由(重要)
Map<Integer, String> map = new HashMap<>();
→ インタフェースで書くことで、実装を後から変更しやすい
例:
Map<Integer, String> map = new LinkedHashMap<>();
5. なぜentrySetが効率的なのか
よく使うループ(entrySet)
for(Map.Entry<Integer, String> entry : hashmap.entrySet()){
System.out.println(entry.getKey() + " : " + entry.getValue());
}
「キーと値を同時に扱うならこれが一番効率的らしい」
なんで?forのループ回数は一緒じゃね?
keySet + get の場合
- keySetでキーを1つ取り出す
- map.get(key) を呼ぶ
- ハッシュ計算して
- 該当ノード探す
→ 毎回「検索処理」が走る
entrySet の場合
- 最初から「キー+値セット」を取り出す
- getKey / getValue はただのフィールド参照
→ 検索が不要
→ entrySetを使った方がループの中身の効率が良い
6. forEachの特徴
メリット
- コードが短い
- 読みやすい(慣れると)
デメリット
- break / continue が使えない
- 複雑な処理には向かない
拡張for文とforEachメソッドの使い分け
- forEach(シンプル処理向き)
map.forEach((k, v) -> System.out.println(k + ":" + v));
- 拡張for(制御したいとき)
for(Map.Entry<Integer, String> entry : map.entrySet()){
if(entry.getKey() == 2) break;
}
7. 計算量のイメージ
- put / get / remove → 平均 O(1)
- 最悪 → O(n)(ハッシュ衝突時)