---
# System prepended metadata

title: Java - 匿名內部類別 & Lambda Expressions
tags: [Java, Basic Java]

---

# Java - 匿名內部類別 & Lambda Expressions
###### tags: `Java` `Basic Java`

## 匿名內部類別
### 1. Syntax:
```
new (class name) or (interface name) () {
    @Override
    method();
};
```
For example:
先建立一個游泳的interface
```
public interface Swim {
    public abstract void swim();
}
```
在主方法直接用new的寫法
```
    public static void main(String[] args) {
        new Swim() {

            @Override
            public void swim() {
                System.out.println("I can swim!!");
            }
        };

    }
```
所謂的"匿名"，其實就是指沒有名字的類別
也就是下面這一段
```
                    {

            @Override
            public void swim() {
                System.out.println("I can swim!!");
            }
        };
```
我們可以使用建立物件的方式把這個沒有名字的類別創建出來，就會變成用new Swim() + 匿名類別
結果就會形成上面所提到的syntax
換句話說，我們這一段code在做的事情，其實就是用匿名內部類別去建立一個物件
```
        new Swim() {

            @Override
            public void swim() {
                System.out.println("I can swim!!");
            }
        };
```
所以如果直接執行這一段code，並不會產生任何結果，因為物件才剛被做出來而已，都還沒call任何方法

### 2. 使用目的：
正常的流程是：先寫一個子類別去繼承父類別，或是接上interface，重寫裡面的方法之後，再到主方法當中用new建立物件，之後用.調用方法。
但是如果這個類/interface**只需要被使用到一次而已**，透過這個流程會相當繁瑣跟多餘。此時就可以使用匿名內部類別的方式進行創立物件與方法使用，會比較方便

完整寫法如下：
```
public class Test {
    public static void main(String[] args) {

        method(new Swim() {

            @Override
            public void swim() {
                System.out.println("I can swim!!");
            }
        }
        );

    }

    public static void method(Swim s) {
        s.swim();
    }
}
```
或是利用多型的寫法
```
public class Test {
    public static void main(String[] args) {

        Swim s = new Swim() {

            @Override
            public void swim() {
                System.out.println("I can swim!!");
            }
        };

        s.swim();
    }
}
```
或是直接invoke方法
```
public class Test {
    public static void main(String[] args) {

        new Swim() {

            @Override
            public void swim() {
                System.out.println("I can swim!!");
            }
        }.swim();
    }
}
```

## Lambda Expressions
### 1. 使用目的：簡化匿名內部類別的寫法
舉例說明：
一個正常的匿名內部類別寫法
```
    public static void main(String[] args) {
    
        userInterfaceA(new InterfaceA() {
            @Override
            public void display() {
                System.out.println("Display Anonymous inner class");
            }
        });
    }

        public static void userInterfaceA (InterfaceA a) {
            a.display();

        }

    interface InterfaceA {
        void display();
    }
```
改成Lambda Expression
```
        userInterfaceA(() -> {
            System.out.println("Display Anonymous inner class");
        });
```

### 2. 寫法解釋：
Lambda的概念其實就是一個個函數，你可以根據輸入這個函數的值去決定輸出的值
```
()->{}

(): 匿名內部類別的形式參數
{}: 被覆寫之方法的方法體
```
以上面的code為例
(): 匿名內部類別的形式參數
內部類別InterfaceA()裡面的參數是空白，故寫()即可

{}: 被覆寫之方法的方法體
覆寫的方法為System.out.println("Display Anonymous inner class")，所以就在{}裡面放入這一段code

拼起來就會變這樣：
() -> {System.out.println("Display Anonymous inner class");}

### 3. 能用Lambda Expression簡化的條件：
**只有functional interface才能利用lambda expression
(functional interface是指僅有一個抽象方法的interface)**

如何判斷interface是否為functional interface?

可以利用在interface上面加上@FunctionalInterfaces來判斷，如果產生IDE產生錯誤就代表該interface非functional interface

### 4. Lambda Expression的省略寫法：
#### a. 若覆寫的方法體只有一行，可以將{};都省略不寫
省略前：
```
userInterfaceA(() -> {
            System.out.println("Display Anonymous inner class");
        });
```
省略後：
```
userInterfaceA(() -> System.out.println("Display Anonymous inner class"));
```
#### b. 若只有一個參數，則參數類型與()都可以省略
```
public class Test2 {
    public static void main(String[] args) {
        useDisplayTool(new DisplayTool() {
            @Override
            public void display(String msg) {
                System.out.println("Anonymous inner class " + msg);
            }
        });

        System.out.println("------------------");
        
        //msg就是省略參數類型與()的表達
        useDisplayTool(msg -> System.out.println("Lambda Expression " + msg));

    }


    public static void useDisplayTool(DisplayTool displayTool) {
        displayTool.display("print a message");
    }

    interface DisplayTool {
        void display(String msg);

    }
}
```

#### c. 若方法體只有一行且有return，必須省略return並去掉
```
public class Test3 {
    public static void main(String[] args) {

        useRandomNumber(new RandomNumber() {
            @Override
            public int getNumber() {
                return new Random().nextInt(100) + 1;
            }
        });

        System.out.println("-------------");

        useRandomNumber(() -> new Random().nextInt(100) + 1);
    }


    public static void useRandomNumber(RandomNumber randomNumber) {
        int result = randomNumber.getNumber();
        System.out.println(result);
    }

    interface RandomNumber {
        int getNumber();

    }
}
```

#### d. 有多個參數，參數類型可省略不寫
```
public class Test4 {
    public static void main(String[] args) {

        useCalculator(new Calculator() {
            @Override
            public int calculate(int a, int b) {
                return a + b;
            }
        });

        System.out.println("------------------");
        
        // 這邊可以不宣告a和b的int類型
        useCalculator((a, b) -> a + b);

    }


    public static void useCalculator(Calculator calculator) {
        int result = calculator.calculate(10, 20);
        System.out.println(result);
    }

    interface Calculator {
        int calculate(int a, int b);

    }
}
```

### 5. 大絕招：利用IDEA自動產生
寫完匿名內部類別之後，直接把游標移到class name或interface name上面，按alt + enter，就會出現replace with lambda的提示，直接自動生成