Java 8 で ラムダ式 と ストリーム API が導入されたので、それを独習してみる。
Wikipedia によると、ラムダ式(ラムダ計算)とは「1 つの変換規則と 1 つの関数定義規則のみを持つ、最小のプログラミング言語」だそうである。
学校の数学で f(x) = x + 2 みたいに関数の定義をすることがあるが、この表記に近いものがラムダ式、と解釈した。これを“ラムダ式”として書く場合は λ を使って λx . x + 2 と表現する。
これだけだと関数を定義しただけなので、どうにもならない。これをどう使うかというと、 関数型インターフェイスへ代入する。
@FunctionalInterface interface Foo { int hoge(int x); } public static void main(String[] args) { Foo foo = (x) -> x + 2; System.out.println("result: " + foo.hoge(3)); // result: 5 }
7 行目のように、 new するようなタイミングでラムダ式を代入する。そうすると、インターフェイスで定義されている抽象メソッドがラムダ式で定義したメソッドにオーバライドされる。以降、そのオーバライドされたメソッドにアクセスすると、ラムダ式の内容が実行される。
ラムダ式を代入できる条件(関数型インターフェイスの条件)は:
そのメソッドとラムダ式のインターフェイス(引数)が一致している
とのこと。つまり、オーバライド対象が確定できるものでないとラムダ式を代入できない。
ちなみに、ラムダ式の引数に型宣言を載せることもできる:
Foo foo = (int x) -> x + 2;
また、ラムダ式の処理部分が複数行に渡る場合は中括弧 {} で括ることができる。この場合、戻り値が期待されているものについては return 文を省略できない。
@FunctionalInterface interface Foo { int hoge(int x); // 戻り値あり } @FunctionalInterface interface Bar { void fuga(int x); // 戻り値なし } public void _main(String[] args) { Foo foo = (x) -> { System.out.println("arg: " + x); return x + 2; // 省略不可 }; Bar bar = (x) -> { System.out.println("arg: " + x); x += 2; // return は不要 }; }
関数型インターフェイス の作り方は、前述の通り、抽象メソッドを 1 つだけ定義すれば良い。そうであれば、アノテーション @FunctionalInterface を付けなくても関数型インターフェイスとして利用できるが、付けておくとコンパイル時に関数型インターフェイスとして妥当かどうかチェックしてくれるので、付けた方が良いだろう。。
より詳しく丁寧な解説は次のサイトにあるので、ご覧あれ。
Javaラムダ式 (http://www.ne.jp/asahi/hishidama/home/tech/java/lambda.html)