MapとHashMap

Mapはキーと値のペアのコレクションです。このレッスンでは、Mapの使用方法を学びます。

Mapインターフェースの特徴

特徴 説明
キーと値のペア 各要素にキーと値がある
キーは一意 キーは一意、値は重複可能
順序なし HashMapは順序なし

HashMap

HashMapは最も一般的に使用されるMap実装です。

HashMapの作成

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

Map<String, Integer> map1 = new HashMap<>();
Map<String, Integer> map2 = new HashMap<>(100);  // 指定容量
Map<String, Integer> map3 = new HashMap<>(map1);  // 他のMapから作成

基本操作

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

public class HashMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> scores = new HashMap<>();
        
        // キーと値のペアを追加
        scores.put("Alice", 95);
        scores.put("Bob", 88);
        scores.put("Charlie", 92);
        System.out.println("Map: " + scores);
        
        // 値を取得
        int aliceScore = scores.get("Alice");
        System.out.println("Aliceのスコア: " + aliceScore);
        
        // 値を取得(キーが存在しない場合にデフォルト値を返す)
        int davidScore = scores.getOrDefault("David", 0);
        System.out.println("Davidのスコア: " + davidScore);
        
        // チェック
        System.out.println("Aliceを含む: " + scores.containsKey("Alice"));
        System.out.println("95を含む: " + scores.containsValue(95));
        System.out.println("サイズ: " + scores.size());
        
        // 変更
        scores.put("Alice", 98);  // 古い値を上書き
        System.out.println("更新後のAlice: " + scores.get("Alice"));
        
        // 削除
        scores.remove("Bob");
        System.out.println("削除後: " + scores);
    }
}

putIfAbsent

JAVA
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 95);

// キーが存在しない場合にのみ追加
map.putIfAbsent("Alice", 100);  // 上書きされない
map.putIfAbsent("Bob", 88);     // 追加される

System.out.println(map);  // {Alice=95, Bob=88}

走査方法

方法1:keySetを走査

JAVA
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 95);
map.put("Bob", 88);
map.put("Charlie", 92);

for (String key : map.keySet()) {
    System.out.println(key + ": " + map.get(key));
}

方法2:valuesを走査

JAVA
for (int value : map.values()) {
    System.out.println(value);
}

方法3:entrySetを走査

JAVA
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

方法4:Lambda

JAVA
map.forEach((key, value) -> System.out.println(key + ": " + value));

例:Mapの走査

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

public class MapTraversal {
    public static void main(String[] args) {
        Map<String, Integer> scores = new HashMap<>();
        scores.put("Alice", 95);
        scores.put("Bob", 88);
        scores.put("Charlie", 92);
        
        // entrySetで走査
        System.out.println("=== entrySet走査 ===");
        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        
        // Lambdaで走査
        System.out.println("=== Lambda走査 ===");
        scores.forEach((name, score) -> 
            System.out.println(name + "のスコアは" + score));
    }
}
▶ 試してみよう

TreeMap

TreeMapは赤黒木ベースで、キーが自動的にソートされます。

例:TreeMap

JAVA
import java.util.Map;
import java.util.TreeMap;

public class TreeMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> map = new TreeMap<>();
        map.put("Charlie", 92);
        map.put("Alice", 95);
        map.put("Bob", 88);
        
        // キーでソート
        map.forEach((key, value) -> 
            System.out.println(key + ": " + value));
        // Alice: 95
        // Bob: 88
        // Charlie: 92
    }
}
▶ 試してみよう

LinkedHashMap

LinkedHashMapは挿入順序を維持します。

例:LinkedHashMap

JAVA
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> map = new LinkedHashMap<>();
        map.put("Charlie", 92);
        map.put("Alice", 95);
        map.put("Bob", 88);
        
        // 挿入順序
        map.forEach((key, value) -> 
            System.out.println(key + ": " + value));
        // Charlie: 92
        // Alice: 95
        // Bob: 88
    }
}
▶ 試してみよう

一般的なMapメソッド

メソッド 説明
put(K, V) キーと値のペアを追加
get(K) 値を取得
getOrDefault(K, V) 値を取得、存在しない場合はデフォルト値
putIfAbsent(K, V) キーが存在しない場合に追加
remove(K) キーと値のペアを削除
containsKey(K) キーを含むか
containsValue(V) 値を含むか
keySet() すべてのキーをSetとして取得
values() すべての値をCollectionとして取得
entrySet() すべてのエントリをSetとして取得
size() サイズ
isEmpty() 空かどうか
clear() すべてクリア
putAll(Map) すべて追加

Mapの比較

特徴 HashMap TreeMap LinkedHashMap
順序 順序なし ソート済み 挿入順
実装 ハッシュテーブル 赤黒木 リンクリスト + ハッシュテーブル
パフォーマンス O(1) O(log n) O(1)
nullキー 1つ許可 許可しない 1つ許可

例:単語頻度カウンター

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

public class WordCount {
    public static Map<String, Integer> count(String text) {
        Map<String, Integer> map = new HashMap<>();
        String[] words = text.toLowerCase().split("\\s+");
        
        for (String word : words) {
            map.put(word, map.getOrDefault(word, 0) + 1);
        }
        
        return map;
    }
    
    public static void main(String[] args) {
        String text = "hello world hello java world hello";
        Map<String, Integer> counts = count(text);
        
        counts.forEach((word, count) -> 
            System.out.println(word + ": " + count));
        // hello: 3
        // world: 2
        // java: 1
    }
}

例:グループ化

JAVA
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GroupBy {
    public static Map<String, List<String>> groupByFirstChar(List<String> list) {
        Map<String, List<String>> map = new HashMap<>();
        
        for (String s : list) {
            String key = s.substring(0, 1).toUpperCase();
            map.computeIfAbsent(key, k -> new ArrayList<>()).add(s);
        }
        
        return map;
    }
    
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");
        names.add("David");
        names.add("Eve");
        
        Map<String, List<String>> groups = groupByFirstChar(names);
        groups.forEach((key, value) -> 
            System.out.println(key + ": " + value));
        // A: [Alice]
        // B: [Bob]
        // C: [Charlie]
        // D: [David]
        // E: [Eve]
    }
}

❓ よくある質問

Q HashMapのキーはnullにできますか?
A はい、nullキーは1つだけ許可されます。値は複数のnullを持つことができます。
Q HashMapは重複キーをどのように検出しますか?
A まずhashCodeを比較し、次にequalsを比較します。HashSetと同様です。
Q HashMapはスレッドセーフですか?
A いいえ。マルチスレッドシナリオにはConcurrentHashMapを使用してください。

📖 まとめ

📝 演習

  1. 単語頻度: 文字列内の各単語の出現回数をカウント
  2. グループ化: 学生を成績レベル(優秀/良好/及格/不及格)でグループ化
  3. キャッシュ: HashMapを使用して簡単なキャッシュを実装

次のレッスン

次のレッスンでは、ジェネリクスを学びます — Javaジェネリクスを理解します。

100%