関数型インターフェースの話をします。
突然ですが、以下のコードを見てください。
interface Foo {
public Function<String,String> doIt(Function<Integer,String> f);
}
Foo foo = f -> x -> "ABC" + f.apply(x.length());
System.out.println(foo.doIt(x -> x + "$").apply("DEF"));
これはラムダ式です。
ラムダ式の基本に立ち返って、Main.java
を省略せずに書いてみます。
Foo foo =
(Function<Integer,String> f) ->
{return (String x) -> {return "ABC" + f.apply(x.length());};}
長くなって余計にわからなくなったかもしれませんが、これを部分で見ていきます。
ポイントは、
・どのラムダ式がどの関数型インターフェースの定義をしているのか
・ある時点での戻り値を把握する
の二点だと思います。なので常にこれを意識していきます。
上記のコードは、冒頭の
public Function<String,String> doit(Function<Integer,String> f)
の定義です。
ですので、引数がFunction<Integer,String>
となります。
このFunctionの定義はまだしていない、ということを確認してください。
次に戻り値Function<String,String>
を見てみます。
(String x) -> {return "ABC" + f.apply(x.length());}
String型を引数にとり、String型を返します。
戻り値のFunctionの処理はここで定義されました。
doItの定義と、doItの戻り値の定義が行われました。
次に引数Function<Integer,String>
の定義です。
これはMain.java
の2行目で行っています。
foo.doIt(x -> x + "$").apply("DEF")
x -> x + "$"
がそれです。
あえて書き直すと、
foo.doIt((Integer x) -> {return x + "$";}).apply("DEF")
となります。
Integer型を引数に、String型を返しています。
それぞれの定義を確認したところで、値の流れを見てみます。
まず、doIt()
が呼ばれ、関数の定義(x -> x +"$"
)を渡します。
そして、また別の関数の定義(x -> "ABC" + f.apply(x.length())
)を戻します。
doItが実行された時点では、まだ値は関数の定義のままです。
doIt()
に連なっているapply("DEF")
を実行することで具体的な値が生まれます。
doIt()
から戻ってきたFunction<String,String>
の引数に"DEF"
が渡ります。
値を代入してみると、
"ABC" + f.apply("DEF".length())
ということになります。
"DEF".length()
のInteger型を利用して、引数のFunction<Integer,String> f
が実行されます。
"DEF".length() + "$"
ここではString型の"3$"
が戻ります。
すると、doIt()
の戻り関数は
"ABC" + "3$"
となり、最終的な値は"ABC3$"
です。
ラムダの中のラムダを説明してみました。
何かご意見や補足あれば、よろしくお願いいたします。