はじめに:MapとStreamは最強のコンビ!
Javaを学んでいると、「Mapはよく使うけど、Streamとの連携方法がよくわからない…」という方が多いです。
実は、MapとStreamを組み合わせて使うと、複雑なデータ操作が驚くほどシンプルになります!
このブログでは、Java初心者にもわかるように、MapとStreamを連携させるテクニックを解説します。
1. MapをStreamに変換する基本
まず、MapからStreamを得るには次の3つの方法があります。
✔ entrySet():キーと値の両方を扱いたいとき
1 2 |
map.entrySet().stream() |
これは最も多く使われる方法です。キーと値をペアで処理したい場合に便利です。
✔ keySet():キーだけに注目したいとき
1 2 |
map.keySet().stream() |
✔ values():値だけを処理したいとき
1 2 |
map.values().stream() |
2. よく使うMapとStreamの連携パターン
ここでは実践的な操作例を紹介します。
① 値でフィルタリング(条件に合う要素だけ取り出す)
1 2 3 4 5 6 7 8 9 |
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)
1 2 3 4 5 6 7 8 |
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を再構築します。
③ キーと値の逆転(入れ替え)
1 2 3 4 5 6 7 8 |
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)
1 2 3 4 5 6 7 8 9 |
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
1 2 3 4 5 6 |
Map<String, Integer> newMap = oldMap.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue )); |
✔ キーの重複がある場合:マージ関数を追加
1 2 3 4 5 6 7 8 9 |
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で集める
1 2 3 4 5 6 7 8 9 |
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の値を合計する
1 2 3 4 |
int total = map.values().stream() .mapToInt(Integer::intValue) .sum(); |
✔ 最大/最小の値を持つエントリを取得
1 2 3 4 |
Map.Entry<String, Integer> max = map.entrySet().stream() .max(Map.Entry.comparingByValue()) .orElse(null); |
5. よくあるミスと注意点
❌ Collectors.toMap()で重複キーがあるとエラー!
1 2 3 4 5 6 7 |
// これは例外が出る可能性あり 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の基本をしっかり学びましょう。
さらに、
- コードレビューを受けたい
- 効率的に転職準備したい
- わからないところを教えてほしい
という方には、サイゼントアカデミー がぴったりです!
コメント