---
# System prepended metadata

title: Anonymous Class/Lambda
tags: [Java]

---

 # Anonymous Class
 
 https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html
 
前面我們寫過一些interface, abstract class, 並且有個子類別繼承他們,
但是每次我們要建立一種介面實作, 或是抽象類別的子類, 就要建立一個class, 有時候只是希望一次性使用, 就會很麻煩。

所以我們可以不直接寫子類別, 直接new 一個interface/abstract class,
並且要實作方法。

寫法: ```new InterfaceOrAbstractClass(constructor param) {declaration};```

Example: 
下面範例有三種, Printer class, IPrinter interface, PrinterAbstract abstract class
並且寫了個別的實作方式。

```java
class Printer {
    public void print(String s) {
        System.out.println(s);
    }
}

interface IPrinter {
    void print(String s);
}

class PrinterAbstract {
    public abstract void print(String s);
}
// ---------- in Main.java ----------
public class Main {
    public static void main(String[] args) {
        Printer v = new Printer() {
            @Override
            public void print(String s) {
                System.out.print("Class : " + s);
            }
        };
        v3.print("Hello"); // Class : Hello
        
        IPrinter v2 = new IPrinter() {
            @Override
            public void print(String s) {
                System.out.print("Interface : " + s);
            }
        };
        v3.print("Hello"); // Interface : Hello
        
        PrinterAbstract v3 = new PrinterAbstract() {
            @Override
            public void print(String s) {
                System.out.print("Abstract Class : " + s);
            }
        };
        v3.print("Hello"); // Abstract Class : Hello
    }
}
```
總之class, abstract class, interface寫法都一樣。
# Lambda

https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

如果Interface 的non-static方法只有一個
我們可以把傳統的Interface Anoymous Class改寫成:

`(param) -> statement`

```java=
interface MathFunction {
    void run(int x,int y);
}

public class Main {
    public static void main(String[] args) {

        // 原本寫法
        MathFunction sum = new MathFunction() {
            @Override
            public void run(int x, int y) {
                System.out.println(x + y);
            }
        };
        sum.run(10, 20); // 30
        
        MathFunction multiply = (x, y) -> {
            int result = x * y;
            System.out.println(result);
        };
        multiply.run(10, 20); // 200
        
        MathFunction subtract = (x, y) -> System.out.println(x - y);
        subtract.run(20, 10); // 10
    }
}
```

---

如果param只有一個的話可以省去小括號
```java=
interface MathFunction {
    void run(int x);
}

public class Main {
    public static void main(String[] args) {
        MathFunction pow = x -> System.out.println(x * x);
        pow.run(10,20); //200
    }
}
```


<br>

### Lambda with return value
如果lambda有return值:
有幾種寫法:
```
(param) -> <return value>
  ```
```
(param) -> {
    ...
    return xxx;
}
```

```java=
interface MathFunction {
    int run(int x,int y);
}

public class Main {
    public static void main(String[] args) {
        MathFunction sum = new MathFunction() {
            @Override
            public int run(int x,int y) {
                return x + y;
            }
        };
        System.out.println(sum.run(10,20))); //30
        
        MathFunction multiply = (x,y) -> {
            int result = x * y;
            return result;
        };
        System.out.println(multiply.run(10,20)); //200
        
        //x * y is the return value itself.
        MathFunction subtract = (x,y) -> x - y;
        System.out.println(subtract.run(20, 10)); // 10
    }
}
```
### Method Reference

https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

- static method
  `ClassName::staticMethodName`
- non-static method
  `object::instanceMethodName`
- constructor
  `ClassName::new`

如果Lambda的效果如同呼叫一個方法/建構子, 可以用該方法的Method Reference代替。
```java
class Methods {
    public static int sum(int x, int y) {
        return x + y;
    }
}

class Test {
    public void sum(int x, int y) {
        return x + y;
    }
}
```
---
像是這個加法
```java
(x, y) -> x + y;
```
- 可以寫成
  ```java
  (x, y) -> Methods.sum(x, y)
  Method::sum
  ```

- 如果是非靜態方法, 可以寫成
  ```java
  Test obj = // ...

  (x, y) -> obj.sum(x, y)
  obj::sum
  ```

---
如果是呼叫建構子
```java
(x, y) -> new Point(x, y);
```
可以寫成
```java
Point::new
```

---
哪邊會用到這鬼東西?
最常見的應該是foreach,在許多Collections都會用到
```java=
List<String> list = new ArrayList<>();
list.add("hello1");
list.add("hello2");
list.add("hello3");

for(String s : list)
    System.out.println(s);

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

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