Java8 Method Reference
Java8からLambdaと一緒にMethod Referenceも導入されました。
これにより、今までアノニマスクラスで書いていたものが、LambdaやMethod Referenceで書くことができるようになりました。
例えば、Comparatorの実装は、
Comparator<String> comparator = String::compareTo;
と書くことができるようになりました。
ここで、気になるのは、Method Referenceでは、どんなものがあって、どういう風に書けるのかということ。
Method Referenceには大きく分けて、4種類のものがあるようです。
- スタティックメソッドのMethod Reference
- 任意の型指定によるインスタンスメソッドのMethod Reference
- オブジェクト指定のインスタンスメソッドのMethod Reference
- コンストラクタのMethod Reference
書き方については、4種類すべて同じで、
ClassName::methodName
という書き方をしますが、4種類それぞれで、引数とメソッドが呼び出される形式が違います。
具体的にはそれぞれ、以下のような使い方をします。
スタティックメソッドのMethod Reference
引数がそのまま、スタティックメソッドの引数に割り当てられます。
これに対応するLambdaは以下のようになります。
(arg) -> ClassName.staticMethod(arg);
任意の型指定によるインスタンスメソッドのMethod Reference
第一引数に対して、Method Referenceで与えたメソッドが呼び出される形となります。
そのため、第一引数とMethod Referenceの型が一致しない場合はコンパイルエラーになります。
残りの引数は、インスタンスメソッドの引数として渡されます。
対応するLambdaは以下のようになります。
(arg1, arg2, arg3) -> arg1.instanceMethod(arg2, arg3);
ちなみに、親クラスを指定した場合は、
super::methodName
と書くことができます。
また、ジェネリクスなどで型を明示的に指定したい場合は
ClassName::<Type>methodName
と書くこともできます。
オブジェクト指定のインスタンスメソッドのMethod Reference
こちらは、スタティックメソッドのMethod Referenceと同様に、
すべての引数がそのままインスタンスメソッドの引数に割り当てられます。
これに対応するLambdaは以下のようになります。
CustomClass instance = new CustomClass(); (arg1, arg2) -> instance.instanceMethod(arg1, arg2);
ここで、Method ReferenceとLambdaの違いは、Lambdaで実行する場合、
instanceはfinalもしくはeffectively finalである必要がありますが、Method Referenceではそのような制約はないということです。
その他、以下のような操作も書くことができます。
Supplier supplier = (list.size() > 10 ? list.subList(0,10) : list)::iterator;
ちょっと読み難いですが、ちゃんと動きます。
コンストラクタのMethod Reference
これも基本的には、スタティクメソッドの場合と同じです。
すべての引数がそのままコンストラクタの引数に割り当てられます。
ただし、注意が必要なのは、メソッド名としてnewを使う点です。
そのため、コンストラクタのMethod Referenceだけは以下のような形になります。
ClassName::new;
ちょっと触ってみた感想としては、Lambdaに比べて、引数の関係が直感的でないせいか、
読むのはいいですが、書くのに最初は苦労する感じがしました。(慣れれば問題なさそう)
ただ、便利だとは思うので、可読性を下げない程度に使っていきたいと思います。