【極論ですけど】JavaでforEachを使ったら負けだと思う
正直使い所がわからないんですよね、forEach.
ログとかprintfとかする以外は…
コレクションを更新するな
未だに時々見るのがこういうコード。
List<X> list = new ArrayList<>(); 適当なコレクション.forEach() .map(t -> list.add(t.getXXXX()));
これとっても良くない。
スレッドセーフでない
上記をあまり深く考えずにパラレルストリームにしちゃいますと
List<X> list = new ArrayList<>(); 適当なコレクション.forEach().parallelStream() .map(x -> list.add(x.getXXXX()));
ArrayListに対する追加処理がスレッドセーフでないため、確率的に不具合が起きてしまいます。*1
パラレルにしなければいい…のですが、Project Lambdaの目的の一つがマルチコアへの対応なわけで、「parallelStreamを使って並列化できないものはラムダ式で書くな」くらいに私は思っています。(私の勝手ルールではありますが)
Lambdaで更新するの「関数」でない
Lambda式内では外で定義した変数に代入ができません。
これは、「状態」を極力排除することによって、バグの入り込む余地を減らすため… と私は認識しています。
ですが、上記のようにコレクションに対する操作や、Setterでの代入はJavaの言語仕様上できてしまいます。
…とはいえ、できるからやっていい、というものでもないと思います。
「リストを作る」と明確に書く方法がある
List<X> list = 適当なコレクション.stream() //parallelも可
.map(X::getXXXX)
.collect(Collector.toList());
そもそもこのように、リストを作るための書き方が用意されているのに、これを使わずに汎用的なforEachでなんとかする… というのは美しさに欠けます。
更新しないとなると、forEachは出力くらいしか使いみちがないのでは
上で書いたとおり、コンパイルエラーにはならない… とはいえ、Lambda式内で何かを「更新」するのは不適切と考えます。
そうなると、冒頭に書いたとおり、何かの出力くらいしか使いみちがないなぁ… ということになり、
よっぽどのことがない限り、「forEachを使ったら負け」だと思うのです。
*1:私が経験したことのある事象だと、「適当なコレクション」よりも多い要素がlistに追加されるという謎現象が発生し、その要素をgetするとnullが入ってる → ヌルポで落ちる というものを何度かみました。