JavaのMapとStream完全連携術|初心者でもわかるフィルタ・変換・集約テクニック集

Java

はじめに:MapとStreamは最強のコンビ!

Javaを学んでいると、「Mapはよく使うけど、Streamとの連携方法がよくわからない…」という方が多いです。

実は、MapとStreamを組み合わせて使うと、複雑なデータ操作が驚くほどシンプルになります!

このブログでは、Java初心者にもわかるように、MapとStreamを連携させるテクニックを解説します。


1. MapをStreamに変換する基本

まず、MapからStreamを得るには次の3つの方法があります。

✔ entrySet():キーと値の両方を扱いたいとき

map.entrySet().stream()

これは最も多く使われる方法です。キーと値をペアで処理したい場合に便利です。

✔ keySet():キーだけに注目したいとき

map.keySet().stream()

✔ values():値だけを処理したいとき

map.values().stream()

2. よく使うMapとStreamの連携パターン

ここでは実践的な操作例を紹介します。


① 値でフィルタリング(条件に合う要素だけ取り出す)

Map<String, Integer> map = Map.of("A", 10, "B", 5, "C", 15);

Map<String, Integer> result = map.entrySet().stream()
    .filter(e -> e.getValue() >= 10)
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        Map.Entry::getValue
    ));

→ 「A」と「C」だけが新しいMapに残ります。


② 値の変換(たとえばString→Integer)

Map<String, String> map = Map.of("A", "100", "B", "200");

Map<String, Integer> result = map.entrySet().stream()
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        e -> Integer.valueOf(e.getValue())
    ));

→ 値の型を変換してMapを再構築します。


③ キーと値の逆転(入れ替え)

Map<String, Integer> map = Map.of("A", 1, "B", 2);

Map<Integer, String> result = map.entrySet().stream()
    .collect(Collectors.toMap(
        Map.Entry::getValue,
        Map.Entry::getKey
    ));

→ キーと値の立場を入れ替えたMapが作られます。


④ Map<K, List<V>> をフラットに展開(flatMap)

Map<String, List<String>> map = Map.of(
    "fruits", List.of("apple", "banana"),
    "veggies", List.of("carrot")
);

List<String> result = map.values().stream()
    .flatMap(List::stream)
    .collect(Collectors.toList());

→ 全てのリスト要素をまとめて1つのリストにできます。

3. Streamで加工した後にMapに戻す方法

✔ 基本形:Collectors.toMap

Map<String, Integer> newMap = oldMap.entrySet().stream()
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        Map.Entry::getValue
    ));

✔ キーの重複がある場合:マージ関数を追加

List<String> items = List.of("apple", "banana", "apple");

Map<String, Long> countMap = items.stream()
    .collect(Collectors.toMap(
        Function.identity(),
        s -> 1L,
        Long::sum
    ));

"apple"の出現回数をカウントするような処理も可能!


✔ 順序を保ちたい場合:LinkedHashMapで集める

Map<String, Integer> sortedMap = map.entrySet().stream()
    .sorted(Map.Entry.comparingByKey())
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        Map.Entry::getValue,
        (v1, v2) -> v1,
        LinkedHashMap::new
    ));

→ ソートした順序をそのまま保持したMapが作れます。


4. Map×Streamの応用テクニック

✔ Mapの値を合計する

int total = map.values().stream()
    .mapToInt(Integer::intValue)
    .sum();

✔ 最大/最小の値を持つエントリを取得

Map.Entry<String, Integer> max = map.entrySet().stream()
    .max(Map.Entry.comparingByValue())
    .orElse(null);

5. よくあるミスと注意点

❌ Collectors.toMap()で重複キーがあるとエラー!

// これは例外が出る可能性あり
Map<String, String> errorMap = List.of("A", "A").stream()
    .collect(Collectors.toMap(
        s -> s,
        s -> "value"
    ));

解決法:マージ関数を指定!


❌ nullキーやnull値が含まれているとNullPointerExceptionの原因に

Map.of(...)はnullを許さない
HashMapput()ではnullを許すことが多いが、Stream内では要注意!


❌ 順序が必要なのにLinkedHashMapを使っていない

→ ソート結果などは順序を保たないと意味がない!
LinkedHashMap::new を忘れず指定しましょう!


6. まとめ:MapとStreamを自由に使いこなそう!

やりたいことStreamの使い方
条件で抽出filter()
値を変換map()
全部1リストにまとめたいflatMap()
キー・値の入れ替えtoMap() with Entry
重複キーに対応したMap作成toMap() with merge function
ソート順を保つMap作成LinkedHashMap::new

おわりに:MapとStreamを使いこなせばプロっぽさが出る!

MapのデータをStreamで加工できるようになると、コードが短く・きれいに・早く書けるようになります。

最初は難しく感じるかもしれませんが、よく使うパターンを覚えておくだけでOKです!

まずは、
👉 絶対にJavaプログラマーになりたい人へ。
でMapとStreamの基本をしっかり学びましょう。

さらに、

  • コードレビューを受けたい
  • 効率的に転職準備したい
  • わからないところを教えてほしい

という方には、サイゼントアカデミー がぴったりです!

コメント

タイトルとURLをコピーしました