LoginSignup
13

More than 5 years have passed since last update.

forループからStream API移行に関する適当な感想

Posted at

Java 8から鳴物入りで導入されたStream APIと、古き良きforループからの移行論争について適当な感想。「※個人の感想です。」

適当にググって出てくる紹介ページの基本論調としては、「forループなんて時代遅れ!これからは全部Stream APIで処理すべし!forループは全部書き換えろ!」が多数派な印象。まあ、新技術の紹介が目的だからそうだよねという感じ。

一方で、無理やりStream APIで書くためにpeek()中間操作を副作用のあるロジック記述に使ってたり、forEach/forEachOrdered終端操作の違いも気にせず使ってたりするのを見かけると、そこまでしてStream APIを積極推進すべきかぁ?とも思う。

結構な割合で、ちょっとparallelストリームに変えるだけで「正しく動く保証のない」Stream処理が書かれている気がする。sequentialにしか正常動作しないなら、気張ってStream APIで書き換えなくてもいいのではという気分になる。インデクス値必須なら古典的forループも悪くないし、単純な要素走査なら拡張forループで十分なこともあるでしょ?(ループ内処理は適切に構造化されている前提)

Stream APIの真価は逐次/並列処理のシームレス統合で、それはJSR-335でも掲げられていたはず。一方で、高速化を目的とする並列処理で捉えると、そのループは最適化対象に値する処理量・データ量なのかに疑問符。最内ループだけいくら頑張っても駄目。早すぎる最適化は諸悪の根源。

その意味で、よくあるStream APIのサンプルは局所化されすぎてるし(サンプルだから仕方ないけど…)、上位の処理構造でデータ並列を効果的に使えるのかという疑問はある。大局的にはFork/Joinタスク並列の方がずっと効果あるんじゃない?残念ながら使い勝手は今一つで、だからこそStream APIが導入されたんだけど。

あとStream API並列処理でちゃんと処理性能出すには、裏方の仕組みを理解していないとやっぱり無理だと思う。Spliterator特性とかCollector特性とか、まだ解説記事も少ない印象。あと並列化オーバーヘッド無視されすぎ。並列処理は魔法じゃないんですよ。

結局のところは、手続型で副作用ベースの記述がされていたforループを、関数型へのパラダイムシフトなしに見た目だけStream API使っても上手くないという話か。表層的な新機能紹介よりも、考え方がなにより重要ではという感想。関数型云々言い出すと怖いからこのへんで。

参考資料:

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
13