セミコロンレスJavaはJava8の夢を見るか?
こんにちは.
続編の変数についてはこちら.
ボケーッとセミコロンレスJavaの事を考えていたら,そういえばStreamAPIはセミコロンレスJavaの技法にかなり影響を与えるのではと思いはじめました.
というのも,基本的にStreamAPIで書いたものをほぼそのままセミコロンレスJavaとして書くことができるのです.
StreamAPIで書いたものを使えるということはループを読みやすい形でセミコロンレスJavaでも書くことが出来ます.
セミコロンレスJavaについてはなぎせさんの記事を参照してください.
http://d.hatena.ne.jp/Nagise/20120407/1333767870
また,StreamAPIを使わないJava8時代のセミコロンレスJavaもなぎせさんが既に書かれているのでそちらを参照してください.
http://d.hatena.ne.jp/Nagise/20131111/1384170146
セミコロンレスJavaの基本とStreamAPI
簡単な例として0から10までを出力するコードを考えてみます.
今までのセミコロンレスJavaでは以下のように書いていました(main内のみを抜粋).
for (int i : new int[]{0}) { while (i <= 10) { if (null == System.out.printf("%d\n", i++)) {} } }
変数は拡張for文を応用することで利用できます.
セミコロンレスJavaでは戻り値の型がvoidのメソッドをそのまま呼び出せません.
ですが,戻り値の型がvoidでないメソッドはif文の条件式内で呼び出し,何らかの値と比較することで使用できます.
普通のJavaでStreamAPIを用いて書くと次のようになりますね.
IntStream.rangeClosed(0, 10) .forEach(System.out::println);
セミコロンレスJavaではStreamAPIの戻り値がvoidのメソッドは考えずにコードを書いていくことにします.
戻り値がvoidのメソッドといえば先ほど使った終端操作のforEachですね.
セミコロンレスJava with StreamAPIではforEachを別のものに置き換えればこっちのものです.
StreamAPIのイディオムをほぼそのままセミコロンレスJavaでも使うことが出来ます.
さて,forEachと同様の機能を持つ中間操作としてpeekが提供されています.
これは中間操作上の値を覗き見る事が出来ます.
主にデバッグ用途で提供されていますが,セミコロンレスJavaでは実質的にforEachとして機能します.
中間操作のため戻り値は同じStreamです.
IntStream.rangeClosed(0, 10) .peek(System.out::println) // IntStream
続いて終端操作を呼びださなければ中間操作であるpeekは実行されません.
適当に値を返す終端操作を見つけてあげましょう.
ここでは要素数を返すcountを用います.
countはStreamやプリミティブ型用のIntStreamなど全てのStreamで利用できます.
IntStream.rangeClosed(0, 10) .peek(System.out::println) .count(); // int
この一連のルールを元に先ほどのコードを書き換えてみます.
まず,forEachで書いていたものをpeekに変えます.
そして,countメソッドを呼び出します.
この式をそのままif文の条件式に持ってきて適当な値と比較します.
if (java.util.stream.IntStream.rangeClosed(0, 10) .peek(System.out::println) .count() == 0) {}
直感的で読みやすいStreamAPIをほぼそのままセミコロンレスJavaでも使うことが出来ました.
FizzBuzzなんかも簡単に書けます.
Streamで書くと以下のようになりますね.
IntStream.rangeClosed(0, 100) .map(i -> i % 15 == 0 ? "FizzBuzz" : i % 3 == 0 ? "Fizz" : i % 5 == 0 ? "Buzz" : "" + i) .forEach(System.out::println);
これもほぼそのままセミコロンレス化できます.
if (java.util.stream.IntStream.rangeClosed(0, 100) .map(i -> i % 15 == 0 ? "FizzBuzz" : i % 3 == 0 ? "Fizz" : i % 5 == 0 ? "Buzz" : "" + i) .peek(System.out::println) .count() == 0) {}
ラムダ式+StreamAPI,ステキ!