Java初心者の壁 ラムダ式を理解する(2)
前回の記事ではラムダ式を理解するための足がかりとして匿名クラスについて書きました。
匿名クラスとラムダ式は書き方が違うだけで同じもの
実は匿名クラスとラムダ式は同じことを違う書き方で表現しているだけなのです。
実際の処理を匿名クラスとラムダ式でそれぞれ記述して比較してみましょう。
今回サンプルで実装するのは、ラムダ式と一緒によく登場するList.sortです。 メソッドについてよく知らない人は、Javadocを眺めてみてください。 それでもピンとこない人はListの中身をソートするメソッド、くらいに捉えればOKです。
シグネチャはvoid sort(Comparator<? super E> c)
となっています。Comparator型の引数を渡してあげればよいですね。
今回は、sortメソッドの実装までは詳しく触れませんが、sortメソッドに渡されるComparatorによって振る舞いが変化します。
つまり、このComparatorこそがソートのアルゴリズムで、それを自分で実装することができます。
匿名クラスで実装
List<String> list = Arrays.asList("aa", "b", "ccc"); list.sort(new Comparator<String>() { public int compare(String str1, String str2) { return str1.compareTo(str2); } });
自分で実装できます!とか言っておきながら、内部ではString.compareToに移譲しています(笑) 今度は同じ処理をラムダ式で書いてみましょう。
ラムダ式で実装
List<String> list = Arrays.asList("aa", "b", "ccc"); list.sort((str1, str2) -> str1.compareTo(str2));
一見難解ですが、記述量はかなり減りましたね。 ではどうしてこの2種類の書き方が同じになるのか見ていきましょう。
関数型インターフェース
今回実装したComparatorは関数型インターフェースと呼ばれるものです。 関数型インターフェースとは、抽象メソッドが一つだけ定義されているインターフェースのことです。 この関数型インターフェースを利用することで、コンパイラはごく僅かな情報からシグネチャを特定できます。
書かなくても良いものを消す
匿名クラスでの実装
List<String> list = Arrays.asList("aa", "b", "ccc"); list.sort(new Comparator<String>() { public int compare(String str1, String str2) { return str1.compareTo(str2); } });
sortの引数の型がComparatorであることは、sortのシグネチャから特定できるので消す。
List<String> list = Arrays.asList("aa", "b", "ccc"); list.sort( public int compare(String str1, String str2) { return str1.compareTo(str2); } );
Comparatorクラスには抽象メソッドはcompareしかないため、可視性、返り値、メソッド名、引数の型は特定できるので消す。
List<String> list = Arrays.asList("aa", "b", "ccc"); list.sort( (str1, str2) { return str1.compareTo(str2); } );
compareはintを返すことがわかっているので、メソッドの中身を一行だけ書いておけばそれがreturn文だと特定できるのでreturnは消す。
List<String> list = Arrays.asList("aa", "b", "ccc"); list.sort( (str1, str2) { str1.compareTo(str2); } );
残った引数と式を->
でつなぐ
List<String> list = Arrays.asList("aa", "b", "ccc"); list.sort((str1, str2) -> str1.compareTo(str2));
ね。簡単でしょ?