【JavaSilver】ラムダ式

# ラムダ式

* 基本的な定義方法
Barインタフェースのfunc()メソッドをオーバーライドした処理
Bar b = (String name) -> { return "Hello" + name;};					
 
* 引数の型が省略可能
Bar b = (name) -> { return "Hello" + name;};
 
* 引数が1つの場合、()が省略可能	
Bar b = name -> { return "Hello" + name;};
※引数なしメソッドや引数が複数ある場合は、()を省略できない。		
  
* オーバーライドの処理が1文の場合、{}が省略可能。
{}を省略した場合、return文を省略。
Bar b = name -> "Hello" + name;

* ラムダ式から参照されるローカル変数は、finalまたは事実上のfinalである必要がある。

<table>
  <caption>関数インタフェース</caption>
  <thead>
    <tr>
      <th>インタフェース名</th>
      <th>抽象メソッドの<br>シグネチャ</th>
      <th>説明</th>
    </tr>
  </thead>
  <tr>
    <td>Predicate< T ></td>
    <td>Boolean test(T t)</td>
    <td>引数1つ(T型)、戻り値あり(boolean型)</td>
  </tr>
  <tr>
    <td>Function< T , R ></td>
    <td>R apply(T t)</td>
    <td>引数1つ(T型)、戻り値あり(R型)</td>
  </tr>
  <tr>
    <td>Consumer< T ></td>
    <td>void accept(T t)</td>
    <td>引数1つ(T型)、戻り値なし</td>
  </tr>
  <tr>
    <td>Supplier< T ></td>
    <td>T get()</td>
    <td>引数なし、戻り値あり(T型)</td>
  </tr>
</table>

* 引数は参照型のみ指定することができる。	
* Consumerは各要素に対する処理を行う。											

1. インタフェースの実装クラスを定義する方法	
```java                                  
@FunctionalInterface	
interface Foo {
    public void func();
}

class Foolmpl implements Foo {
    @Override 
    public void func() {
        System.out.println("lambda");
    }
}	

class Test {		
    public static void main(String[] args) {
        Foo f = new Foolmpl();
        f.func();
    }
}	
```

2.　インタフェースの実装クラスを定義する方法	
```java							
@FunctionalInterface
interface Foo {														
    public void func();		
}

class Test {
    public static void main(String[] args) {
        Foo f = () -> {System.out.println("lambda");};				
        f.func();		
    }
}
```

3.　ラムダ式を定義する方法
```java										
class Test {	
    public static void main(String[] args) {
        // 1.オブジェクト生成については、左辺の型(Foo型)から推論できるため省略可能
        Foo f = // new Foo() {
            //2.Fooインタフェースは「関数型インタフェース」であるため、
            // オーバーライドすべきメソッド名も推論できるため省略可能
            // @override
            //3.func()メソッドの引数定義…残しておくべき定義
            /* public void func*/() //{
                //4.オーバーライドした際の処理…残しておくべき定義
                System.out.println("lambda");
            // }
        // };
        f.func();
    }
}
```
3の引数と4の処理を->の「アロー演算子」でつないで定義するのがラムダ式

```java                                            
class Test {	
    public static void main(String[] args) {
        Foo f = () -> System.out.println("lambda");
        f.func();
    }
}
```
最初の()はfuncメソッドの引数を表し、->{}の中身はfuncメソッドの実装内容になります。
f変数にはFooを実装した無名クラスのインスタンスが代入されます。
つまり、ラムダ式とはインターフェースを実装したインスタンスを生成する式といえます。


                                              
#### 無名クラス
**抽象クラス**
```java
X Abstract a = new Abstract (); // 抽象クラスはインスタンス化できない
```
```java
public abstract class Abstract {
    public abstract void test ();
}

Abstract a = new Abstract () { // →無名クラス
    public abstract test () {
        System.out.println("test");
    }
};
```
この書き方だとコンパイル・実行が可能

**インタフェースクラス**
```java
X IF a = new IF (); // インタフェースクラスはインスタンス化できない
```
```java
public interface IF {
    void test ();
}

IF a = new IF () { // →無名クラス
    public void test () {
        System.out.println("test");
    }
};
```
この書き方だとコンパイル・実行が可能


* ラムダ式で使う変数は実質的にfinalでないといけない。

```java:実装例
import java.util.function.Supplier;

public class Sample {
    void sample() {
        int i = 0;
        Supplier<Integer> foo = () -> i;
        i++;
        System.out.println(foo.get());
```
```:実行結果
コンパイルエラー
```

* ローカル変数とラムダ式で宣言している変数名が重複している。

```java:例題
import.java.util.function.Customer;			
						
public class Sample {			
    public static void main(String[] args) {		
        final String val = "Hello, Lambda";	
        Customer<String> func = (val) -> System.out.println(val);	
        func.accept("Hello, Java");	
    }		
}
```
```:実行結果
コンパイルエラー
```