匿名クラス・ラムダ式・メソッド参照をほんのり理解する

主にラムダ式について書きます。

#ラムダ式は何ができるのか
メソッドを変数のように扱える。
メソッドの引数にメソッドを渡せる。
匿名クラスと同じことをより簡単な記述で書ける。

##ラムダ式のお決まり事
関数型インターフェースの抽象メソッドをオーバーライドする必要がある。
※関数型インターフェース　＝　１つだけ抽象メソッドを持つインターフェース。

##基本の書き方
(型　引数名)　ー＞　｛処理１；｝；

```java
(Object o) -> {System.out.println(o);};
```

#普通 → 匿名クラス → ラムダ式　→　メソッド参照の順番に書いてみる
ラムダ式は**実は抽象メソッドをオーバーライドしているだけ**なのです。
それを理解するために
・普通にオーバーライド
・匿名クラスでオーバーライド
・ラムダ式でオーバーライド
・メソッド参照
という４つで書いてみます。

今回は関数型インターフェースConsumerの抽象メソッドacceptをオーバーライドして実装していきます。
##普通
```java:Consumerインターフェース
@FunctionalInterface
public interface Consumer<T> {
   void accept(T t);
//...
}
```

まずはConsumerインターフェースを「implements」で普通に実装して、acceptメソッドをオーバーライドする方法です。

```java:普通の実装
import java.util.function.Consumer;

public class Lambda2 implements Consumer<String> {

	@Override
	public void accept(String s) {
		System.out.println(s);
	}

	public static void main(String[] args) {
		Lambda2 lam2 = new Lambda2();
		lam2.accept("普通");
	}
}
```

##匿名クラス
次に匿名クラスです。
@Overrideのところがポイント。

```java:匿名クラスで実装
import java.util.function.Consumer;

public class lambda3 {

	public static void main(String[] args) {
		Consumer<String> func = new Consumer<String>() {
			@Override
			public void accept(String s) {
				System.out.println(s);
			}
		};
		func.accept("匿名クラス");
	}
}
```

##ラムダ式
最後にラムダ式でConsumerインターフェースを実装する方法。
acceptメソッドをラムダ式でオーバーライドしています。

```java:ラムダ式で実装
import java.util.function.Consumer;

public class Lambda1 {

	public static void main(String[] args) {

		Consumer<String> func = (s) -> {System.out.println(s);};
		func.accept("ラムダ式");

		// 省略記法。上記と同じ処理。
		Consumer<String> func2 = s -> System.out.println(s);
		func2.accept("ラムダ式省略記法");
			}
}
```

## メソッド参照
・参考
[【Java】ラムダ式、メソッド参照](https://nompor.com/2017/11/09/post-923/)

メソッド参照はすでにあるメソッドを関数型インターフェースの抽象メソッドに突っ込む。
ここでは参照されるメソッド()がaccept()に突っ込まれている。

書き方

+ staticメソッド：クラス名::メソッド名
+ インスタンスメソッド：変数名::メソッド名 

```java
public class MethodSansyou implements Consumer<String>{

	@Override
	public void accept(String t) {}

	static void 参照されるメソッド (String t) {
		System.out.println(t);
	}

	public static void main(String[] args) {
		
		Consumer<String> c = MethodSansyou::参照されるメソッド;
		c.accept("メソッド参照");
	}
}
```

やっていることは普通のも匿名クラスもラムダ式も全て**acceptメソッドをオーバーライドしているだけ**です。
１、acceptメソッドをオーバーライド　`Consumer<String> func = (s) -> {System.out.println(s);};`
２、acceptメソッド呼び出し　`func.accept("ラムダ式");`

#Stream APIで同じことをしてみる
Stream APIでラムダ式を使うと最強らしいのでやってみます。

先ほどと同様に以下の順番です。
・普通に実装
・匿名クラスで実装
・ラムダ式で実装
・メソッド参照で実装

```java:Consumerインターフェース
@FunctionalInterface
public interface Consumer<T> {
   void accept(T t);
//...
}
```


```java:普通
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class Normal implements Consumer<String>{
	@Override
	public void accept(String s) {
		System.out.println(s);
	}

	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("1");
		list.add("2");
		list.add("3");

		// forEachでlistの中身を取り出す。
		Normal n = new Normal();
		list.forEach(n);// forEachの引数にConsumer<String>型を渡す
	}
}
```

```java:匿名
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class Tokumei {

	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("1");
		list.add("2");
		list.add("3");

		list.forEach(new Consumer<String>() {
			@Override
			public void accept(String s) {
				System.out.println(s);
			}
		});
	}
}
```

```java:ラムダ式
import java.util.ArrayList;
import java.util.List;

public class Lambda4 {

	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		list.add("1");
		list.add("2");
		list.add("3");

		list.forEach(s -> System.out.println(s));
	}
}
```

ラムダ式だと非常に短い記述で済みますね！
implementsも@Overrideも書かなくてよいのでかなり楽です。

```java:メソッド参照
public class StreamMethodSansyou {

	public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");

        list.forEach(System.out::println);
	}
}
```

##forEachの仕組み
forEachは引数にConsumer<T>型を取ります。

```java
forEach(Consumer<T> t)
```

forEachはacceptを繰り返し実行するメソッドです。
オーバーライドされたacceptが繰り返し実行されています。

### メソッドの引数にメソッドを渡す

```java
public class StreamMethodSansyou {

	public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        Consumer<Integer> func = s -> {
        	s = s * 2;
        	System.out.println(s);
        };
        list.forEach(func); //2 4 6
	}
}
```

#代表的な関数型インターフェース
関数型インターフェースは自分で書くこともできますが、よく使うものは既に用意されています。

##Consumer
引数を受け取るだけで戻り値なし。
引数の型：T

```java
@FunctionalInterface
public interface Consumer<T> {
   void accept(T t);
//...
}
```

##Function
引数Tを受け取りRを返す。
引数の型：T
戻り値型：R

```java
@FunctionalInterface
public interface Function<T, R> {
   R apply(T t);
//...
}
```

##Predicate
引数Tを受け取りbooleanを返す。
引数の型：T
戻り値型：boolean

```java
@FunctionalInterface
public interface Predicate<T> {
   boolean test(T t);
//...
}
```
##Supplier
引数を受け取らずTを返す。
戻り値型：T

```java
@FunctionalInterface
public interface Supplier<T> {
   T get();
//...
}
```

#まとめ
ラムダ式を使うとかなり記述を減らせることがわかりました。
普通　→　匿名クラス　→　ラムダ式 →　メソッド参照という風に書き換えていくと慣れていけそうです。
配列やコレクション使用時には積極的に活用しようと思います。