#なんの記事?
仕事中暇だったので、java8から追加されたラムダ式について調べた。
そのイメージでまとめた記事。
#記事の対象者は誰?
Javaの基本は抑えたぜ!
ラムダ式?ネットで検索しても詳しすぎてわかんねー(^q^)
って人向け。
#ラムダ式ってなんなん?
ラムダ式は、JDK1.8で導入された構文。
なんか最近見る、e->System.out.println(e.toString())とか。
関数型インターフェースってやつに代入できる物。
##メリットなんなの?
別にラムダ式を覚えたからと言って、すごいアルゴリズムがかけたり、モテたりするわけではない。
ただ、ドヤ顔はできるかも?
私が感じたラムダ式のメリットは、コードを短くかけるなーというところ。
あと、後々の話になるが関数型インターフェイス簡単に作れるわーってところ。
例えば、Runnableインターフェイスを実装する場合。
今までの場合、匿名クラスを使用すると・・・。
public class MyThread {
Thread thread;
public MyThread(){
thread = new Thread(new Runnable(){
@Override
public void run() {
System.out.println("(/・ω・)/私です。");
}
});
}
}
ラムダ式を使用すると・・・。
public class MyThread {
Thread thread;
public MyThread(){
thread = new Thread(()->System.out.println("(/・ω・)/私です。"));
}
}
と、短くなる。うれしくないですか?
###補足
多分、私みたいに、適当にJavaの学習をしていると、「匿名クラス?なにそれ?しらねーよ」となると思う。
匿名クラスの説明は省いて、匿名クラスを使用しないで書いたコードが下のやつになるっぽ。
public class MyThread {
Thread thread;
public MyThread(){
thread = new Thread(new MyRunnable());
}
private class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("(/・ω・)/私です。");
}
}
}
「匿名クラス」を超大雑把に説明すると、名前を付けずにクラスを宣言するやつ。
MyThread01.javaでは、MyThread03.javaみたいに、MyRunnableって名前のクラスがないでしょ?
匿名クラスだからだよ!
##ラムダ式の説明。
匿名クラスで実装したものと、ラムダ式で実装したものとの対応を可視化してみた。
私のイメージはこう!
すごい大雑把ですね!
ところで、青の部分は何なの?って疑問になりませんか?
青の部分は、引数ですね!
Runnableインターフェイスは引数がないから分かりづらいですね!
引数がある自作インターフェイスで見てみますか!
先ほど同様、匿名クラスを使用した場合・・・。
public class MyTestClass {
public MyTestClass(){
new Watashidesu(new MyTestInterface() {
@Override
public void watashidesuPrint(String str) {
System.out.println(str+"私です!");
}
});
}
private class Watashidesu{
String str ="(/・ω・)/";
public Watashidesu(MyTestInterface mti) {
mti.watashidesuPrint(str);
}
}
private interface MyTestInterface{
public void watashidesuPrint(String str);
}
}
ラムダ式を利用した場合・・・。
public class MyTestClass {
public MyTestClass(){
new Watashidesu((e)->System.out.println(e+"私です"));
}
private class Watashidesu{
String str ="(/・ω・)/";
public Watashidesu(MyTestInterface mti) {
mti.watashidesuPrint(str);
}
}
private interface MyTestInterface{
public void watashidesuPrint(String str);
}
}
ちょっと、インターフェイスとインターフェイスを利用したクラスを作成したため、可読性が悪くなりましたね!
public MyTestClass()の部分だけを見てください!
先ほど青色で囲んだ部分に違いがありますね!
匿名クラスのほうには、【String str】が!
ラムダ式には【e】が入っています!
つまりラムダ式のeは、String型のstrを示しているんです('ω')
型宣言されていませんが、それは、なんか上手くやってくれます。
ちなみに、(e)を(String e)に変えても問題はありませんよ。
なんか型宣言しないと気持ちが悪いという方は、宣言しましょう。
明記していてくれたほうが、読む側からすれば、いいかもですね。
あっ!あと、ラムダ式のeは、変数名の規約を守れば何でもおkです!
普通は短くするっぽいです。(ラムダ式内でしか使われないから?)
##ラムダ式の利用どころ
いままでのサンプルを見ていると、インターフェイスの代わりにラムダ式を入れるって感じでしたね。
そう!ラムダ式の利用どころは、インターフェイスの変数に代入するときなのです!
つまり!
関数型インターフェイス に ラムダ式 を代入
(例)
Runnable r に ()=>{}を代入!
多分、私のように適当にJavaを学んだ初心者は、インターフェイスと聞いて、「implementsの後ろにつくあれかー」「とりあえずRunnableをimplements!」、くらいの知識だと思います。コードを書いていくうちにインターフェイスの便利さに気づいてくると思います。「デザインパターン」で検索することをお勧めしますよ。
また、ラムダ式が代入できるインターフェイスは関数型インターフェイスのみです。
関数型インターフェイスってなんやねんってなるとおもいますが、そんな難しいものではありません。
関数型インターフェイスもインターフェイスの一部なのですが、ちょっとだけ制約があります。
とりあえず、Runnableのapiをのぞいてみましょう。
API : Runnableインターフェイス
はい!抽象メソッドが一つだけですね!
そうです!抽象メソッドが一つだけのインターフェイスが関数型インターフェイスなのです!
こういうやつは、上記みたいにラムダ式で代入できます。
ちなみに、以下のインターフェイスも関数型インターフェイス!
API : Comparableインターフェイス
API : BiFunctionインターフェイス
API : Functionインターフェイス
逆にこういうやつは関数型インターフェイスではありません。
API : Listインターフェイス
よって、ラムダ式で代入できません!
###補足
基本的に抽象メソッドは1つですが、たまに、複数個存在するのに関数型インターフェイスがある場合があります。
Objectクラスにあるpublicメソッドがインターフェース内に抽象メソッドとして定義されている場合、複数個存在します。
アノテーションFunctionalInterfaceがついていれば、関数型インターフェイスで間違いありません。
##まとめ
今回は、ラムダ式の記述法とか関数型インターフェイスの説明とかでした。
多分最初はラムダ式を書くことに抵抗を感じると思いますが、使っていくうちに慣れてきます。
「()->」を何度も書くといいかもですね!コードは見るだけでなくて書くことで理解が深まると思います。
ラムダ式とかを多用するのはStream関連だと思いますので、そのうち、それについてもザックリまとめます。
間違い・わからない所があれば、コメントください。
以上、ありがとうございました。