---
# System prepended metadata

title: 方法參照
tags: [method reference, Java, "Java\_Lambda", 方法參照]

---

# 方法參照
Lambda 表示式實作的匿名方法包含三部分 : 
1. 方法參數(argument list)。
2. 箭頭符號(arrow token)，為`->`
3. 方法內容(body)。

方法內容(body)只是呼叫另一個方法(method)，可將此改寫為「方法參照(method reference)」，讓語法更簡潔。

## 四種方法內容
依據被呼叫的方法的種類和來源，可分為以下四種 : 
1. 方法是靜態(static)，來自某類別。
2. 方法是實例(instance)，來自 lambda 之「外」的參考變數。
3. 方法是實例(instance)，來自 lambda 之「內」的參考變數。
4. 使用`new`呼叫建構子。

## 範例
實作 Arrays 類別的 sort 方法，所用的參數`Comparator<? super T> c`

### 靜態方法
```java=
class Utility1 {
    static int comparatorImp1(String s1, String s2) {
        return s1.compareToIgnoreCase(s2);
    }
}
```
```java=
String[] strings = {"a", "b", "c", "d", "e"};
// Arrays.sort(strings, (a, b) -> Utility1.comparatorImp1(a, b));
Arrays.sort(strings, Utility1::comparatorImp1)
```

### lambda 之「外」的參考變數
```java=
class Utility2 {
    int comparatorImp2(String s1, String s2) {
        return s1.compareToIgnoreCase(s2);
    }
}
```
```java=
String[] strings = {"a", "b", "c", "d", "e"};
Utility2 u2 = new Utility2();
// Arrays.sort(strings, (s1, s2) -> u2.comparatorImp2(s1, s2));
Arrays.sort(strings, u2::comparatorImp2);
```

### lambda 之「內」的參考變數
```java=
String[] strings = {"a", "b", "c", "d", "e"};
Utility2 u2 = new Utility2();
// Arrays.sort(strings, (s1, s2) -> s1.compareToIgnoreCase(s2));
Arrays.sort(strings, String::compareToIgnoreCase);
```
> 參考來自 lambda 表示式內與靜態方法很像，都是用類別名稱。可藉由方法是否為 static 區分。
> 本例來說，String 類別的 compareToIgnoreCase() 方法非 static 方法，所以為內部參數的實例方法。

### 使用`new`呼叫建構子
`ClassName::new`

```java=
public class MethodReferenceDemo {
    String x;
    public MethodReferenceDemo() {}
    public MethodReferenceDemo(String s) {
        this.x = s;
    }
    public void printX() {
        System.out.println(x);
    }
    
    private static MethodReferenceDemo createWithoutInput() {
        // Supplier<MethodReferenceDemo> supplier = () -> new MethodReferenceDemo();
        Supplier<MethodReferenceDemo> supplier = MethodReferenceDemo::new;
        return supplier.get();
    }    
    private static MethodReferenceDemo createWithInput() {
        // Function<String, MethodReferenceDemo> function = s -> new MethodReferenceDemo(s);
        Function<String, MethodReferenceDemo> function = MethodReferenceDemo::new;
        return function.apply("inputValue");
    }
    
    public static void main(String[] args) {
        createWithoutInput();
        createWithInput().printX();
    }

```
> 使用方法參照呼叫建構子時，語法上是使用無參數的 Supplier 介面。若要產生需要參數的建構子，須改用 function 介面。
> 若參數超過兩個，則先定義符合該個數的 FunctionalInterface。
```java=27
    public MethodReferenceDemo(String x, Integer y, Double z) {
        this.x = y + z + x;
    }
    @FunctionalInterface
    private interface FunctionDemo<One, Two, Three, Four> {
        public Four apply(One one, Two two, Three three);
    }
    private static MethodReferenceDemo test() {
        FunctionDemo<String, Integer, Double, MethodReferenceDemo> function = MethodReferenceDemo::new;
        return function.apply("", 0, 0.0);
    }
}
```
###### tags: `Java` `method reference` `方法參照`