はじめに: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を許さない
→ HashMapやput()では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の基本をしっかり学びましょう。
さらに、
- コードレビューを受けたい
- 効率的に転職準備したい
- わからないところを教えてほしい
という方には、サイゼントアカデミー がぴったりです!


コメント