Java ラムダ式を目的と成り立ちから理解する

<h1>はじめに</h1>
Javaの学習を始めて間も無いです。
私が学習を進めていく中で理解に苦労したのがラムダ式です。
そんなラムダ式を自分なりに理解できたので、自分のような初心者の方向けにメモを残します。
内容に間違いがある可能性がありますのでご了承ください。

<h1>ラムダ式とは</h1>
<b>無名クラス</b>を表現する際に使われる記法のこと。
コード量を少なくできると言うメリットがある。

ただ楽に書けるというだけで、使わなくても問題ない。

<h1>無名クラスとは</h1>
<b>インナークラス</b>を省略したもの。
無名クラスをを使うことで、インナークラスをわざわざ定義することなく実現できる。
コードを量を少なくできると言うメリットがある。

ただ楽に書けるというだけで、使わなくても(インナークラスを使っても)問題ない。

<h1>インナークラスとは</h1>
クラスの中に定義されたクラス。
インナークラスは内部に定義されたメソッドなどの内容を外部に漏らさずに提供することを目的とし、<b>情報隠蔽</b>を実現する。

<h1>ラムダ式の目的</h1>
上記をまとめるとラムダ式の目的は、<b>定義されたメソッドを情報隠蔽を保持したまま使う</b>ことである。

<h1>上記を踏まえて、ラムダ式を使うまで</h1>

<h2>①情報隠蔽を実現した簡単なプロジェクトを作る</h2>

```Java
------------------------
|パッケージA              | 
| Sampleインターフェース    | //公開
| SampleImplementsクラス | //非公開
| SampleSupplyクラス     | //公開
------------------------
------------------------
|パッケージB              | 
| Mainクラス             |
------------------------
```
上記のようなプロジェクト構成があったとする。


```Sample.java
public interface Sample{
    public void hello(); 
}
```
↑　Sampleインターフェースはhello（）という抽象メソッドを提供しているのみ。


```SampleImplements.java
class SampleImplements implements Sample{
    @Override 
    public void hello(){
        System.out.print("Hello");
    }
}
```
↑　SampleImplementsクラスはSampleインターフェースを実現したクラス。
処理内容などは隠蔽したいのでパッケージ外には非公開にする。

```SampleSupply.java
public class SampleSupply{
    public static Sample create(){
        return new SampleImplements();
    }
}
```
↑　SampleSupplyクラスは、SampleImplementsクラスのインスタンスをSample型として返すだけのクラス。

```Main.java
public class Main{
    Sample sample = SampleSupply.create();
    sample.hello();
}
```
↑ これでMainクラスは公開されているSampleインターフェースとSampleSupplyクラスの情報を知っているだけで、SampleImplementsクラスの機能を使うことができる。
また、SampleImplementsクラスに修正があった場合も、Mainクラス側の変更をする必要がなくなる。

しかし懸念点があり、SampleImplementsクラスが同じパッケージ内の別のクラスにアクセスされてしまう可能性がある。
そこでインナークラスを使用する。

<h2>②インナークラスを定義する</h2>
```SampleSupply.java
public class SampleSupply{
    public static Sample create{
        //インナークラスのインスタンスを生成して返す
        return new SampleSupply.new SampleImplements();
    }
    
    //privateのインナークラスを定義
    private class SampleImplements implements Sample{
        @Override
        public void hello(){
            System.out.print("Hello");
        }
    }
}
```
↑　これでSampleImplementsクラスがSampleSupplyクラス以外からアクセスされる心配がなくなった。
また、使用する側のMainクラスは変更する必要がない。

しかし、わざわざ一つのメソッドを実現するためにクラスを定義するのは面倒である。
ここで無名クラスを使用する。

<h2>③無名クラスを定義する</h2>
```SampleSupply.java
public class SampleSupply{
    public static Sample create(){
        return new Sample{
            //クラスの定義
            @Override
            public void hello(){
                System.out.print("Hello");
            }
         }
     }
}
```
↑ これでインナークラスをさらに省略して記述できた。

しかし、それでもまだコードが長いので最後にラムダ式を使用する。

##④ラムダ式を使用する
```SampleSupply.java
public class SampleSupply{
    public static Sample create(){
        return () -> {System.out.print("Hello");};
    }
}
```
↑ これで初めは一つのクラスだったSampleImplementsクラスを一行で記述することができた。

##なぜ無名クラスをラムダ式で省略できるのか？
それは、Sampleインターフェースが抽象メソッド一つのみを持つ<b>関数型インターフェース</b>だからである。
（関数型インターフェースはラムダ式を使って実装することを目的としたインターフェース）

上記のラムダ式の詳細は

```java
(引数) -> { 処理の内容 }

//上記のhelloメソッドは引数なしのため空欄になる
```
Sampleインターフェースの抽象メソッドは一つしかないため自動的にメソッドが選択される(天才)
今回はSampleインターフェースはhelloメソッドしか持っていない為、ラムダ式ではhelloメソッドに対する引数と処理内容を記載すれば良い。

ここまで散々SampleSupplyクラスを修正してきましたが、使用する側のMainクラスは全く変更する必要がなく最初の状態のまま使えると言う点もポイントです。


<h1>最後に</h1>
ラムダ式を記述するまでの流れを書きましたが、この内容ではただスマートなコードを書けるだけです。
ラムダ式の本質はStreamAPIに使用するところにあると思います。
時間があればStreamAPIについても書こうと思います。