スポンサーリンク

Streamがわかる!map・filter・collectとtoMapエラー対策

スポンサーリンク
この記事は約14分で読めます。
スポンサーリンク

JavaのStream、

  • 「1行にギュッと書かれていて読めない…」
  • 「mapとかfilterとか、結局なにをしてるの?」
  • 「toMapを書いたら、なぞのエラーで落ちたんだけど…」

こんな経験、ありませんか?

でも安心してください。

Streamはむずかしい魔法じゃなくて、データを流れ作業みたいに加工して、最後に集める書き方なだけです。

この記事では、

  • filter=「いる・いらないを選ぶ」
  • map=「形を変える」
  • collect=「集める」

を、ぜんぶ日本語で説明します。

さらに、

「まずはfor文で考える → それをStreamにする」比較や、
初心者さんが一番つまずく toMapの『同じキーがあります』エラーも、
「なぜ起きるのか」「どう直せばいいのか」を例つきで解説します。

筆者
筆者

読み終わるころには、Streamを上から順に読んで、
「今なにしてるか」がちゃんと頭に浮かぶ状態になりますよ。
では、一緒にいきましょう!

  1. Streamは何ができる?まずは1文でつかむ
    1. Streamをひと言でいうと
    2. 「流れ作業」のたとえでイメージ
    3. よく出てくる3つの言葉(map / filter / collect)
  2. map・filter・collectを日本語に直すと最速でわかる
    1. filter=いる・いらないをえらぶ(例:偶数だけ)
    2. map=形を変える(例:文字列→長さ)
    3. collect=あつめる(List / Set / Mapにする)
    4. よくある勘違い:mapは「Map型にする」じゃない
  3. for文→Streamへ書き換えて「順番」を体で覚える
    1. まずはfor文で書く(読みやすい基準を作る)
    2. 同じ処理をStreamにする(横に並べて比較)
    3. mapとfilterの順番は「何を先に楽にするか」
    4. デバッグのコツ:途中でprintして流れを見る(peekの考え方)
  4. 超シンプルなサンプルで3つを分解して読む練習
    1. 数字List:filter→map→collect(王道)
    2. 文字列List:mapで整形、filterで検索
    3. 「一気に書かれたStream」を3行に分ける書き方
  5. collect(toMap())は「キー・値・エラー対策」の3点セット
    1. toMapの基本形(キーと値を決める)
    2. 「同じキーがあります」エラーの正体
    3. 直し方1:どっちを残すか決める(マージ関数)
    4. 直し方2:先にgroupingしてからMapにする(重複が自然なとき)
    5. 直し方3:キーを重複しない形に作り直す
  6. ありがちエラー集:原因→直し方が一発でわかる
    1. Nullが混ざって落ちる(null対策の基本)
    2. 型が合わない(ジェネリクス迷子)
    3. collectの結果が思った形と違う(List / Set / Mapの選び方)
  7. いつ使う?「現場の使いどころ」具体例3選
    1. 検索:条件に合うデータだけ取り出す
    2. 変換:表示用の形に整える(DTO / 画面表示)
    3. 集計:ID→名前の辞書を作る、重複はまとめる
  8. まとめ:今日から迷わないチェックリスト
    1. 読み方の手順(filter→map→collect)
    2. toMapで困ったら見る3項目
    3. 最後にひとこと
  9. よくある質問
スポンサーリンク

Streamは何ができる?まずは1文でつかむ

Streamをひと言でいうと

Streamは、データを上から順に流しながら、加工して、最後にまとめる仕組みです。
これだけ覚えてもらえれば、今日はもう半分クリアです。
「流す → 途中で手を加える → 最後に集める」、この流れがStreamの正体です。

「流れ作業」のたとえでイメージ

たとえば工場の流れ作業を想像してください。
ベルトコンベアにデータ(部品)が流れてきて、

  • いらないものをはねる
  • 形をちょっと変える
  • 箱に詰める

こんな作業を順番にやっていますよね。
Streamもまったく同じで、順番に処理して、最後に完成品を受け取るだけなんです。

よく出てくる3つの言葉(map / filter / collect)

Streamで必ず出てくるのが、この3つです。

  • filter:いる・いらないを選ぶ
  • map:形を変える
  • collect:まとめて箱に入れる
筆者
筆者

今は「名前を見たことがある」くらいでOKです。
次の章で、この3つを日本語感覚でしっかり固めていきますよ。

map・filter・collectを日本語に直すと最速でわかる

ここが一番大事なところです。

Streamが読めない原因の8割は、この3つの役割がごちゃっとしているからです。
なので今回は、むずかしい話は抜きで、日本語一言+超短い例で固定しますね。

filter=いる・いらないをえらぶ(例:偶数だけ)

filterは「条件に合うものだけ残す」係です。
Listの中から、「これは使う」「これは捨てる」を決めるだけです。

たとえば数字のListがあったとして、
「偶数だけ欲しい」と思ったら、filterの出番です。

  • 入ってくる:1, 2, 3, 4, 5
  • 残す   :2, 4

ポイントは、数は増えないことです。
filterは「選別」なので、減るか、そのままか、どちらかです。

map=形を変える(例:文字列→長さ)

mapは「中身を別の形に変える」係です。
数を数えたり、文字列を加工したりします。

たとえば、

  • 入ってくる:「apple」「banana」
  • 出ていく :5、6

こうやって、別の型に変わるのがmapです。
数は減らなくてもOKですし、増えもしません。
「1つ来たら、1つ返す」がmapの基本です。

collect=あつめる(List / Set / Mapにする)

collectは「最後にまとめる」係です。
Streamの途中では、まだ完成品じゃありません。
collectを呼んで、やっとListやMapになります。

よく使うのはこの3つです。

集め方日本語でいうと
Listそのまま順番に集める
Set重ならないように集める
Mapキーと値で辞書を作る

「どの箱に入れるか」を決めるのがcollectだと思ってください。

よくある勘違い:mapは「Map型にする」じゃない

初心者さんが一番ハマるのがここです。
mapはMapを作るものではありません。

  • map:形を変える
  • collect(toMap):Mapに集める

名前が似ているだけで、役割はまったく別です。
この違いを覚えた瞬間、Streamの霧が一気に晴れます。

ミニクイズ(おまけ)

「文字列を大文字にして、Listにする」
このとき使うのはどれでしょう?

  • map
  • filter
  • collect

答えは、mapで大文字にして、collectでListにするです。

筆者
筆者

こんな感じで、日本語で追えるとStreamは怖くなくなりますよ。

for文→Streamへ書き換えて「順番」を体で覚える

「Streamが一気に書かれていて読めない…」

これはもう、順番が見えていないだけです。
なのでこの章では、いきなりStreamを書きません。
まずfor文で“正解の形”を作ってから、Streamに変えます。

まずはfor文で書く(読みやすい基準を作る)

例として、
「数字のListから偶数だけ取り出して、2倍にして、Listにする」
という処理を書いてみます。

for文だと、だいたいこんな流れになります。

  • 1つずつ取り出す
  • 偶数かチェックする
  • 2倍にする
  • Listに追加する

上から読めば、何をしているか一目で分かりますよね。
この「読みやすさ」が基準です。

同じ処理をStreamにする(横に並べて比較)

さっきの流れを、そのままStreamに置き換えます。

  • 偶数だけにする → filter
  • 2倍にする → map
  • Listにする → collect

Streamは、for文の処理を横に並べただけなんです。
突然むずかしくなったわけじゃありません。

mapとfilterの順番は「何を先に楽にするか」

よく出る疑問がこれです。

「filterとmap、どっちが先なんですか?」

答えは、楽なほうを先にやるです。

  • 先に減らせるなら → filterを先
  • 形を変えたほうが条件を書きやすいなら → mapを先

正解は1つじゃありません。
読みやすい順・考えやすい順が正解です。

デバッグのコツ:途中でprintして流れを見る(peekの考え方)

「本当にこの順で動いてる?」と思ったら、途中で中身を表示してみましょう。

最初はprintlnで十分です。
「今ここを通ってるな」と分かるだけで、理解が一気に進みます。

慣れてきたら、
「流れをのぞき見る」ための考え方としてpeekがあります。
ただし、デバッグ用だと思ってください。
本番処理は、あくまでfilter・map・collectが主役です。

筆者
筆者

ここまでで、「Streamは上から順に読むもの」という感覚が、体に入ってきたはずです。
次は、もっと短い例で分解して読む練習をしますよ。

超シンプルなサンプルで3つを分解して読む練習

ここからは、「読む練習」です。
Streamは1行で書けてしまうのが落とし穴です。
最初は遠慮なく、3行に分けて読みましょう

数字List:filter→map→collect(王道)

まずは王道パターンです。
「数字のListから、偶数だけ取り出して、2倍して、Listにする」。

頭の中では、こう読んでください。

  • filter:偶数だけ残す
  • map:2倍にする
  • collect:Listに集める

Streamは、この日本語を上から書いているだけです。
処理の順番がズレなければ、もう迷いません。

文字列List:mapで整形、filterで検索

次は文字列です。

たとえば、
「空白を消してから、特定の文字を含むものだけ探す」
こんな処理、よくありますよね。

この場合の読み方はこうです。

  • map:文字列を整える(空白カットなど)
  • filter:条件に合うものだけ残す
  • collect:Listにする

さっきと順番が違いますが、理由が分かればOKです。
「先に形を整えたほうが、探しやすい」からですね。

「一気に書かれたStream」を3行に分ける書き方

実務コードでは、
filter・map・collectが1行にズラッと並んでいることが多いです。

そんなときは、こうしてください。

  • 1行目:filter(選ぶ)
  • 2行目:map(変える)
  • 3行目:collect(集める)

そして各行の上に、「今なにしてるか」を日本語コメントで書きます。

筆者
筆者

これだけで、「読めないStream」→「読めるStream」に変わります。
次は、みんなが一度は落ちる toMap の話に進みましょう。

collect(toMap())は「キー・値・エラー対策」の3点セット

toMapは、Streamの中でも一番つまずきやすいボスです。でも安心してください。

toMapは、この3つをセットで考えるだけで怖くなくなります。

① キーは何?
② 値は何?
③ 同じキーが出たらどうする?

この順で、必ず口に出してください。

toMapの基本形(キーと値を決める)

toMapは「Mapを作るcollect」です。なので、まず決めるのはこの2つです。

  • キー:検索に使うもの
  • :そこにひもづけたい情報

たとえば、

「ID → 名前」の辞書を作りたいなら、
キーはID、値は名前です。

ここまでは、みなさんだいたい理解できています。
問題は、次です。

「同じキーがあります」エラーの正体

toMapでよく見るこのエラー、実は意味はとてもシンプルです。

「同じキーが2回出てきました。
でも、どうするか聞いてません。」

Javaは、

  • 新しい方を残すのか
  • 古い方を残すのか
  • まとめたいのか

何も勝手に決めてくれません。
なので、決めていないとエラーになります。

直し方1:どっちを残すか決める(マージ関数)

「どっちか残ればOK」な場合は、
マージのルールを教えてあげます。

  • 新しい方を残す
  • 古い方を残す

このどちらかを決めるだけです。
「重複はあるけど、片方でいい」
こんなときは、この方法が一番シンプルです。

直し方2:先にgroupingしてからMapにする(重複が自然なとき)

もし、
「同じキーに、複数の値があるのが普通」
なら、無理にtoMapしないでください。

この場合は、grouping(グループ分け)してからMapにします。

  • キー:ID
  • 値:そのIDにひもづくList

重複が「仕様」なら、
まとめてしまうのが正解です。

直し方3:キーを重複しない形に作り直す

そもそも、
「そのキー、本当に1つに決まりますか?」
というケースもあります。

  • 日付だけだと重なる
  • 名前だけだと同姓がいる

こういうときは、
キーの設計が間違っている可能性があります。

ID+日付、
ID+連番、
など、重ならない形に作り直すのも立派な解決策です。

toMapで迷ったら、
「キー・値・重複どうする?」
この3点を思い出してください。
次は、さらに細かいありがちエラー集に進みますよ。

ありがちエラー集:原因→直し方が一発でわかる

ここでは、Streamを書いていて
「うわ、また落ちた…」となりがちなポイントをまとめます。
症状 → 原因 → 1行の直し方の順で見ていきましょう。

Nullが混ざって落ちる(null対策の基本)

症状

処理の途中で、いきなりNullPointerException。

原因

Listの中に、nullが混ざっています。
mapでメソッドを呼んだ瞬間に落ちます。

直し方

選択肢は2つだけです。

  • filterでnullを落とす
  • mapで別の値に置き換える

「nullも大事に扱う」は、最初は考えなくてOKです。
消すか、置き換えるか、どちらかに決めましょう。


型が合わない(ジェネリクス迷子)

症状

赤線だらけで、エラー文が長い…。

原因

「入力」と「出力」の型を見失っています。

Streamは、

  • 入力:T
  • 出力:R

この矢印(T → R)を意識してください。

  • filter:T → T
  • map:T → R
  • collect:R → List / Set / Map

ここが分かると、エラー文が読めるようになります。

collectの結果が思った形と違う(List / Set / Mapの選び方)

症状

「あれ?Listだと思ったのにMapになってる…」

原因

collectで、どの箱を選んだか忘れています。

直し方

最後に、これを自分に聞いてください。

  • 順番がほしい? → List
  • 重複はいらない? → Set
  • 検索したい? → Map

collectは、ゴールを決める場所です。
ゴールを決めれば、迷いません。

筆者
筆者

この章のエラーは、実務でも本当によく出ます。
次は、「じゃあ、いつStreamを使うの?」という疑問に答えますよ。

いつ使う?「現場の使いどころ」具体例3選

ここまで読んで、
「Streamは分かった。でも、実際どこで使うの?」
と思っているかもしれません。
安心してください。使いどころは意外とシンプルです。

検索:条件に合うデータだけ取り出す

一番よく使うのが、検索です。
たとえば、ユーザー一覧から
「有効なユーザーだけ」「年齢が20以上だけ」
こんな条件で絞りたいときです。

  • filter:条件に合うものだけ残す
  • collect:Listにする

for文でも書けますが、
条件が増えても横に足していけるのがStreamの強みです。

変換:表示用の形に整える(DTO / 画面表示)

次に多いのが、変換です。
DBのデータを、そのまま画面に出すことは少ないですよね。

  • map:表示用に形を変える
  • collect:Listにまとめる

「中身は同じだけど、見せ方を変える」
こういう処理は、Streamがとても得意です。

集計:ID→名前の辞書を作る、重複はまとめる

最後は、集計・辞書化です。
IDから名前をすぐ引けるようにしたい、
そんなときはMapが便利です。

  • collect(toMap):ID → 名前
  • 重複があるなら、まとめるかルールを決める

ここで大事なのは、
重複の扱いは仕様で決まるということです。
「技術的にどうするか」より先に、
「業務的にどうあるべきか」を考えましょう。

筆者
筆者

この3つ、検索・変換・集計
これが見えたら、「あ、ここStreamだな」と気づけるようになります。
次はいよいよ、まとめです!

まとめ:今日から迷わないチェックリスト

最後に、
Streamで迷わなくなるためのチェックリストを置いておきます。
困ったら、ここに戻ってきてください。

読み方の手順(filter→map→collect)

Streamは、上から日本語で読むだけです。

  • filter:何を残す?
  • map:どう変える?
  • collect:どこに集める?

「今この行で何してる?」
これが答えられれば、ちゃんと読めています。

toMapで困ったら見る3項目

toMapは、必ずこの3点セットです。

  • キーは何?
  • 値は何?
  • 同じキーが出たらどうする?

ここを決めずに書くと、
あのエラーは必ず出ます。

最後にひとこと

それでも迷ったら、for文に戻ってOKです。
for文で書けた処理は、必ずStreamに直せます。

for文 → Stream → またfor文。
この行き来ができるようになると、Streamは「怖いもの」から「便利な道具」に変わります。

今日から、ぜひ使ってみてくださいね 👍

よくある質問

Q
Streamって、無理に使わなくてもいいですか?
A

はい、無理に使う必要はまったくありません
for文のほうが読みやすいなら、それが正解です。
Streamは「検索・変換・集計」がハマる場面で使うと便利な道具、くらいに思ってください。

Q
mapとfilterの順番、毎回迷います…
A

めちゃくちゃ普通です。
基本は、先に楽になるほうを先にでOKです。

  • 数を減らせる → filter先
  • 形を変えたほうが条件が書きやすい → map先

「どっちが正解?」ではなく、
「どっちが読みやすい?」で決めて大丈夫です。

Q
Streamは速いんですか?for文より性能いい?
A

ケースバイケースです。
多くの場合、体感できる差はほぼありません
それよりも、
「読みやすいか」「ミスしにくいか」を優先したほうが、結果的に良いコードになります。

Q
toMapの重複キーエラー、毎回出ます…
A

それはもう、みんな通る道です。
toMapを書くときは、必ずこう自分に聞いてください。

  • 同じキー、出ない?
  • 出たらどうしたい?

ここを決めるだけで、
あのエラーは怖くなくなります。

Q
Streamが長くなって読めなくなります…
A

あります、実務あるあるです。
そんなときは、1行で書かないのがコツです。

  • filter
  • map
  • collect

を改行して、
各行に日本語コメントを書いてください。
それだけで、「読めるStream」に変わります。

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