lambdaについて調べてみた その2
【前提条件】
【概要】
前回はラムダの基本的な書き方を調べ、
各インターフェイスのシンタックスシュガーに
似た動きをするのがわかりました。
(スコープの扱いが違うらしいですが、まだ試していません)
前回は省略できる部分を省略せずかいていたので、
今回は省略した書き方について調べて見ました。
【事前準備】
今回のサンプルを実行する準備として
↓のメソッドを作成しています。
private static void execConsumer(final Consumer<String> consumer) { System.out.println("========== consumer start =========="); consumer.accept("consumer test"); System.out.println("========== consumer end =========="); System.out.println(""); } private static void execFunction(final Function<String, String> function) { System.out.println("========== function start =========="); System.out.println(function.apply("function test")); System.out.println("========== function end =========="); System.out.println(""); }
毎回、変数に突っ込んで実行するのを書くのが面倒なので、
各インターフェイスを受け取って実行するメソッドを作りました。
見た目がわかりやすいように余計な出力を実行していますが。
【省略していく】
[パラメータあり、戻り値なし]
まずはパラメータあり、戻り値なしのパターンの
書き方について見ていきます。
execConsumer( (String p) -> { System.out.println(p); } );// No.1 execConsumer( (String p) -> System.out.println(p) );// No.2 execConsumer( (p) -> System.out.println(p) );// No.3 execConsumer( p -> System.out.println(p) );// No.4
No.1は省略なしの書き方で、パラメータの型と名前を括弧でくくって、
実行するステートメントにセミコロンつけて、全体を中括弧でくくって・・・
省略しててコンパイルエラーで困ったとときに
この書き方に立ち戻ってエラーの原因探すといいと思います。
No.2はNo.1から中括弧とステートメントのセミコロンをはずしました。
実行するステートメントが1つの場合、ステートメントのみの記述で実行できます。
No.3はNo.2からパラメータの型の指定をはずしています。
今回のサンプルのexecConsumerのパラメータはConsumer
ジェネリクスで指定した型が適用されるためパラメータの型が不要です。
final Consumer<String> consumer = (p) -> System.out.println(p);
↑の書き方と同じです。
No.4はパラメータの指定から括弧を外しています。
ここでメソッド参照と言う新しい機能を使ってみます。
execConsumer(System.out::println);
パラメータの指定もなくなりました。
「オブジェクト::メソッド名」とやると
ラムダで受け取るパラメータをそのままメソッドに渡してくれます。
最後にステートメントが複数ある場合です。
execConsumer(p -> {
System.out.println(p);
System.out.println(p);
});
ステートメントが複数ある場合、省略できるのはパラメータの型と括弧だけです。
[パラメータあり、戻り値あり]
次にパラメータあり、戻り値ありのパターンの
書き方について見ていきます。
execFunction( (String p) -> { return "p : " + p; } );//No.1 execFunction( p -> { return "p : " + p; } );//No.2 execFunction( p -> "p : " + p );//No.3 // No.4 execFunction(p -> { System.out.println("test"); return "p : " + p; });
No.1は省略なしの書き方です。
パラメータあり、戻り値なしのパターンと同じです。
こちらは戻り値があるのでreturnを使っています。
No.2はNo.1からパラメータの指定を変数名のみにしました。
No.3はreturnと括弧を省略しています。
ステートメントが1つだけの場合はreturnも省略できます。
No.4はステートメントが複数ある場合です。
[メソッド参照]
先ほど使ったメソッド参照で参照できるのは
staticメソッド、インスタンスメソッド、コンストラクタです。
(公式ドキュメントでは4種類です。インスタンスメソッドについては2種類あります。)
っで、まずは準備として適当なstaticメソッドを作ります。
public class Sample { private static String sampleMethod(final String value) { return value + " - " + value; } }
Stringを取って、Stringを返します。
では、メソッド参照を使ってみます。
execFunction(Sample::sampleMethod);//No.1 execFunction("a"::concat);//No.2 execFunction(String::toUpperCase);//No.3 execFunction(p -> p.toUpperCase());//No.3-1 execFunction(String::new);//No.4
No.1は作成したstaticメソッドを参照しています。
No.2は特定のオブジェクト(今回は"a")のメソッドに
ラムダで受け取ったパラメータを渡して実行しています。
No.3はNo.2と同じくインスタンスメソッドを使用していますが、
ラムダで受け取ったパラメータのインスタンスメソッドを実行しています。
No.3とNo.3-1は同じ結果になります。
No.4はコンストラクタを実行しています。
【まとめ】
省略した書き方について調べて見ましたが、
段階的に省略していけば結構すぐ慣れます。
StreamAPIを使う場合には省略した書き方を
多用することになると思うので、
慣れておかないと読めなくなりそうですね。