進歩についていけない焦りを抱えた50代が、

若手のコードを理解できるようになることを目標に、Java7以降を一から学び直す記録です。

2026年2月15日日曜日

【Java進化史 第17回】Java8 〜データが壊れた日。forEachが危ない理由〜

昔、データが壊れたことがある。

テストでは動いていた。
だが本番で崩れた。

件数が合わない。
値が欠ける。
ときどき例外も出る。

原因は、スレッドセーフではないクラスだった。


■ スレッドセーフとは

複数のスレッドから同時に触っても、 データが壊れないこと。

逆に言えば、 同時に触ると壊れるクラスもある。

そして怖いのは、

テストでは再現しないことがある。

タイミング次第だからだ。


■ 並列処理は、昔は怖かった

Java7まで、 並列処理を書くには自分で守る必要があった。

synchronizedを付ける。
Concurrent系を使う。
共有変数に気を付ける。

だから私は、 並列処理が少し怖かった。


■ Streamでも同じことが起きる

List<String> result = new ArrayList<>();

list.parallelStream()
    .map(Employee::getName)
    .forEach(result::add);   // これ

parallelStreamにすると、 複数スレッドが同時にaddする可能性がある。

ArrayListはスレッドセーフではない。

つまり、 また壊れる可能性がある。


■ ああ、だからforEachは危ないのか

forEachは、 外の変数を触る。

外を触るということは、 共有するということだ。

共有は、並列では危ない。


■ collectという書き方

List<String> result =
    list.parallelStream()
        .map(Employee::getName)
        .collect(Collectors.toList());

collectは、 外の変数を使わない。

だからparallelでも、 安心して書ける。

仕組みの詳しい話までは知らなくていい。

並列にするなら、collectを書く。


■ Stream編、ここまで

最初は、 若手の1行が読めなかった。

そこから、

  • 左から読む
  • 何をやるかを書く
  • forEachは危ないことがある

ここまで来た。

もう、Streamは怖くない。

Java8は、 少しだけ味方になった。




0 件のコメント:

コメントを投稿

【Java進化史 第27回】Java9でSetとMapにも of() が? 〜 なんじゃこりゃ、の続き 〜

前回、こんなコードで手が止まった。 List<String> names = List.of("Tanaka", "Sato", "Suzuki"); List.of() 。 変更できないリストを、一...