Java8では、関数型言語の機能をいろいろ取り入れているようなので試してみた。正直、関数型プログラミングは初心者なので間違っているかもしれないのでこれから書いている内容は鵜呑みにしないようにw
他の投稿が大丈夫かと言うと思い込みで間違っているかもしれないので疑ってかかるようにw
お題は、1から10まで足してみる。
まずは、普通に命令型プログラミンで書いてみる。
public static int test1() {
int sum = 0;
for(int i = 1; i <= 10; i++) {
sum += i;
}
return sum;
}
次は、関数型プログラミング。
public static int test2() {
return IntStream.rangeClosed(1, 10).sum();
}
rangeClosedで1~10のIntStream作ってsum()を呼び出してる。
いやいや、Stream API使っているから一応そうなんだろうけど...
もーちょっと、それっぽくしてみる。
public static int test3() {
return IntStream.rangeClosed(1, 10)
.reduce(0, (int a, int b) -> {
return a + b;
});
}
reduceを使ってみる。最初の引数が初期値で次のラムダ式にラムダ式の実行結果とストリームの値が順番にわたされるような感じになるので合計が算出される。
話が変わるが、この例のラムダ式はもっと短く書ける。
public static int test3() {
return IntStream.rangeClosed(1, 10)
.reduce(0, (a, b) -> a + b);
}
さらにー
public static int test3() {
return IntStream.rangeClosed(1, 10)
.reduce(0, Integer::sum);
}
Integer::sumは、メソッド参照でIntegerクラスで定義されている。
さて、もっとそれぽっくしてみる。再帰を使って書いてみる。
public static int sum(final int n, final int m) {
if(n >= m) {
return m;
} else {
return n + sum(n + 1, m);
}
}
public static int test5() {
return sum(1, 10);
}
これだと1~10ぐらいまでだとうまく動くんだが、10000までにするとスタックオーバーフローをおこす。
そこで、末尾再帰な書き方に直して、さらに最適化する必要がある。最適化は、最終的な動作を再帰呼び出しでなくイテレートするように書くこと。
まず、末尾再帰な書き方。
public static int sum2(final int t, final int n, final int m) {
if(n > m) {
return t;
} else {
return sum2(t + n, n + 1, m);
}
}
public static int test6() {
return sum2(0, 1, 10);
}
つぎに末尾再帰最適化なんだが、Java8では勝手にやってくれるようだ。このプログラムの10のところを10000にしてもエラーになんない。よんだJavaで関数型プログラミングする本では、最適化やってたんだが。勝手に最適化が効かない場合があるのかもしれない。最適化は、必要になった時にまた調べて書くことにする。
コメント