0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Java Streamはいつ使う?for文との使い分けと保守性を整理する

0
Posted at

Streamの map() や toList() を理解してくると、

「では、for文よりStreamを使った方がいいのか?」

という疑問が出てきた。

実際にコードを見比べてみると、Streamだから保守性が高い、for文だから古い、という単純な話ではなかった。

今回は、どんな処理ならStreamが読みやすく、どんな処理ならfor文の方が読みやすいのかを整理する。


Streamはデータ加工と相性がいい

たとえば、

List<ProjectResponse> responses = projects.stream()
        .filter(project -> project.isActive())
        .map(project -> new ProjectResponse(
                project.getId(),
                project.getName()
        ))
        .toList();

この処理は、

Project一覧
↓
activeなものだけ残す
↓
ProjectResponseへ変換
↓
Listにする

という流れ。

上から順番に読むだけで、何をしているか分かりやすい。


filter() は条件に合うものだけ残す

.filter(project -> project.isActive())

は、

projectがactiveなら残す

という意味。

つまり、一覧の絞り込み。

for文なら、

for (Project project : projects) {
    if (!project.isActive()) {
        continue;
    }

    // 処理
}

のような部分に近い。


Streamが向いている処理

Streamは特に、

一覧を条件で絞る
別の型へ変換する
並べ替える
集計する
新しいListを作る

といった処理と相性がいい。

たとえば、

List<ProjectResponse> responses = projects.stream()
        .filter(Project::isActive)
        .map(ProjectResponse::from)
        .toList();

なら、

有効なProjectを残す
↓
ProjectResponseへ変換
↓
Listにする

という目的がコードにそのまま出ている。


for文の方が読みやすい処理もある

一方で、何でもStreamにすればいいわけではない。

たとえば、

projects.stream()
        .map(project -> {
            updateDatabase(project);
            sendRequest(project);
            project.setStatus("DONE");
            return project;
        })
        .toList();

このコードでは、

DB更新
API呼び出し
状態変更

まで map() の中に入っている。

本来 map() はデータを別の形へ変換する処理として読むことが多い。

そこにDB更新やAPI呼び出しまで入ると、処理の目的が分かりにくくなる。


for文なら処理順をそのまま読める

同じような処理をfor文で書く。

for (Project project : projects) {
    updateDatabase(project);
    sendRequest(project);
    project.setStatus("DONE");
}

これは、

DB更新
↓
API呼び出し
↓
status変更

とそのまま読める。

特に、

DB更新
外部API呼び出し
状態変更
例外処理
continue
break

などが多い処理では、for文の方が処理順を追いやすいことがある。


Streamだから保守性が高いわけではない

たとえば、

List<String> names = projects.stream()
        .filter(Project::isActive)
        .map(Project::getName)
        .toList();

なら、

activeなProjectだけ残す
↓
nameへ変換
↓
Listにする

と非常に分かりやすい。

こうした処理ではStreamの方が意図を読み取りやすい。

一方、Streamの中に長い処理を書き始めると、

projects.stream()
        .filter(project -> {
            // 長い処理
            return true;
        })
        .map(project -> {
            // さらに長い処理
            return project;
        });

かえって読みづらくなる。

保守性を考えるなら、

Streamを使っているか
for文を使っているか

ではなく、

その処理の意図がコードから読み取れるか

を見る方が大事だと思った。


toList() の注意点

Java 16以降の Stream.toList() が返すListは変更不可。

たとえば、

List<ProjectResponse> responses = projects.stream()
        .map(ProjectResponse::from)
        .toList();

とした後に、

responses.add(newResponse);

と追加しようとすると、UnsupportedOperationException になる。

つまり、

変換した結果をそのまま読む

用途なら toList() は使いやすい。

一方、

後から要素を追加する
削除する

必要がある場合は注意が必要。


AIがStreamを書きやすい理由

AIが生成するJavaコードでは、Streamを見る機会が多いように感じる。

たとえば、

DBから取得したEntityを
Response DTOへ変換する

という依頼なら、

projects.stream()
        .map(ProjectResponse::from)
        .toList();

は、

変換する
↓
Listにする

という処理を短く表現できる。

そのため、こうしたデータ加工ではAIもStreamを選びやすいのだと思う。

ただし、

AIがStreamを書いた
=
Streamを採用するべき

ではない。

既存コードがfor文中心なら、その書き方に合わせた方が読みやすい場合もある。

チームのメンバーがStreamに慣れているかどうかも保守性に影響する。


自分の中での使い分け

Streamが向いていそうなのは、

絞り込み
変換
並べ替え
集計
新しいListの生成

といったデータ加工。

for文が向いていそうなのは、

DB更新
外部API呼び出し
状態変更
処理順が重要
continue / breakを使う
例外処理が複雑

といった処理。


まとめ

Streamを知ったとき、

for文より新しい書き方

のように感じた。

ただ、実際には役割が少し違う。

for文
→ 処理を繰り返す

Stream
→ データに対する加工を流れとして表現する

という違いがある。

特に、

絞る
↓
変換する
↓
Listにする

という処理ならStreamはかなり読みやすい。

一方、

DBを更新する
↓
APIを呼ぶ
↓
状態を変更する

のように処理手順そのものが重要なら、for文の方が読みやすい場合もある。

「Streamの方がモダンだから使う」ではなく、

この処理なら
どちらの方が意図を読み取りやすいか

で選ぶのがよさそうだと整理できた。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?