せてぃーずノート

Javaのイベント参加レポートとかを書いたりします。

forループ殺すべし。慈悲はない。

うん。言ってみたかっただけなんだ。

JJUG CCC 2014春に行ってきました。
基調講演の『foreach書いたら負け!for禁止!』という言葉のインパクトが強すぎです。
その後のセッションのデモでforが出てくるとツッコミが入っていたくらいです。

とりあえず、マケグミ・サラリマンにならないようにforを潰す練習をしてみました。

一時変数を使ったループの置き換え

一時変数を使ったループはこんな感じで置き換えればよさそうです。

for (int i = 0; i < 100; i++) {
    // 何か処理をする!
}

これをLambdaにしてみるとこんな感じ。

IntStream.range(0, 100).forEach(i -> ここに処理を書く!);

1行で書けるのが素晴らし。

条件に適合したらループを抜けるケース

いきなり自信なくなります。
動いているのは確認してますけど、もっと良いやり方があるとかもしれないので・・・。

例としてはListを先頭から検索していき、条件に該当するものが見つかったらループを抜けるケースです。

for (int i = 0; i < 100; i++) {
     if (condition) {
        // 何か処理をする!
        break;
     }
}

forの方はだんだんウザくなってきました。
これをLambdaで書いてみると、こんな感じになります。

IntStream.range(1, 100).filter(i -> condition).findFirst().ifPresent(i -> 処理を書こう);

filterメソッドで条件を指定し、findFirstメソッドで条件に一致する最初の値に対して処理をおこないます。
条件に該当する数値がない場合は、処理が呼び出されません。
例外じゃないです。

Lambdaにすると読みやすくなったといえます。
それに加え、先頭から要素を探す残念処理を簡単にパラレルで実行できたりもシマス。

IntStream.range(1, 100000).parallel().filter(i -> condition).以下略

途中にparallelメソッドを挟むことで処理が並列で行われるので、条件に一致するものを見つけるまでの時間が早くなります。

決められた件数だけを処理するパターン

リストの最後に到達するか一定の件数を超えたら処理を終了するパターンです。
for文で書くとこんな感じ。

int count = 0;
for (int i = 0; i < 100; i++) {
     if (condition) {
        // 何か処理をする!
        count++;
        if (count == 10) {
            // 10件処理したら終わる
            break;
        }
     }
}

うんざりするようなソースですが、Lambdaならこんなに簡単に書けます。

IntStream.range(1, 100).filter(i -> condition).limit(10).forEach(処理をする!);

limitは上限を設定するメソッドで、条件に該当する要素に対して10件処理をしたら終了になります。
forでやっている時のような一時変数でカウントする必要がないのでスッキリします。
こちらも処理がスレッドセーフなら、parallelにして処理時間を短縮することが出来ると思います。

今日やったことまとめ

一時変数forループもLambdaにすると可読性も上がっていい感じ。
IntStreamには今回使ったfindFirstやlimitだけじゃなく、distinctとかmaxといったフィルタリングするのに便利なメソッドが多いので複雑なループでも大丈夫。

Lambdaこわいにならないように準備しておくのが肝心だと思います。
あとは、Java8を仕事で使う政治的根回しをすることも重要です・・・。
なんで、来月から始まるJava開発がJava6なんですかね、某大手ベンダー=サン・・・