Java 中的方法引用

Josen_Earth發表於2024-09-08

方法引用可以有不同的形式,取決於方法的來源和使用場景。主要有四種形式:

  1. 靜態方法引用

    ClassName::staticMethod
    

    示例:

    Math::max;  // 等價於 (a, b) -> Math.max(a, b)
    
  2. 例項方法引用(特定物件的方法)

    instance::instanceMethod
    

    示例:

    System.out::println;  // 等價於 x -> System.out.println(x)
    
  3. 例項方法引用(任意物件的方法)

    ClassName::instanceMethod
    

    示例:

    String::toLowerCase;  // 等價於 x -> x.toLowerCase()
    
  4. 構造方法引用

    ClassName::new
    

    示例:

    ArrayList::new;  // 等價於 () -> new ArrayList<>()
    
  • 方法引用有四種主要形式:靜態方法引用、例項方法引用(特定物件或任意物件)、以及構造方法引用。它們是簡化 Lambda 表示式的方式。
import java.util.function.Supplier;

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public static void main(String[] args) {
        // 建構函式引用
        Supplier<Person> personSupplier = Person::new;

        // 例項方法引用(任意物件)
        Supplier<String> nameSupplier = personSupplier.get()::getName;

        // 使用例項方法引用
        System.out.println(nameSupplier.get());  // 列印 name
    }
}

Supplier 是 Java 8 引入的一個函式式介面,位於 java.util.function 包中。它的主要作用是提供一個結果,不接收任何輸入引數Supplier 常用於需要延遲計算惰性求值的場景,也就是在需要時提供一個值,而不立即計算或建立它。

Supplier 的定義

Supplier 是一個泛型介面,定義如下:

@FunctionalInterface
public interface Supplier<T> {
    T get();
}
  • T:代表返回值的型別。
  • get():是唯一需要實現的方法,呼叫它會返回型別 T 的值。

使用場景

Supplier 通常用於生成或提供一個值、物件,或者用於懶載入。當我們想要推遲某些計算直到呼叫方真正需要它時,Supplier 就非常有用。

示例 1:基本使用 Supplier

下面的例子展示瞭如何使用 Supplier 來提供一個字串:

import java.util.function.Supplier;

public class SupplierExample {
    public static void main(String[] args) {
        // 使用 Supplier 提供一個字串
        Supplier<String> stringSupplier = () -> "Hello, World!";
        
        // 呼叫 get() 獲取結果
        System.out.println(stringSupplier.get());  // 輸出 "Hello, World!"
    }
}

在這個例子中,Supplier<String> 是一個返回字串的 Supplier,呼叫 get() 方法時返回 "Hello, World!"

示例 2:使用 Supplier 延遲計算

Supplier 還可以用於延遲計算,例如只有在需要的時候才計算某個值:

import java.util.function.Supplier;

public class LazyEvaluationExample {
    public static void main(String[] args) {
        Supplier<Double> randomSupplier = () -> Math.random();
        
        // 延遲生成隨機數
        System.out.println("First call: " + randomSupplier.get());
        System.out.println("Second call: " + randomSupplier.get());
    }
}

每次呼叫 randomSupplier.get() 都會生成一個新的隨機數。這就是 Supplier 的延遲計算的優勢,只有在真正需要時才會執行。

示例 3:使用 Supplier 建立物件

Supplier 還可以用於建立物件,尤其是在建構函式引用中非常常見。

import java.util.function.Supplier;

public class Person {
    private String name;

    public Person() {
        this.name = "John Doe";
    }

    public String getName() {
        return name;
    }

    public static void main(String[] args) {
        // 使用 Supplier 提供一個 Person 例項
        Supplier<Person> personSupplier = Person::new;

        // 延遲建立 Person 物件
        Person person = personSupplier.get();
        System.out.println("Person's name: " + person.getName());  // 輸出 "John Doe"
    }
}

在這個例子中,Person::new 是構造方法引用,返回一個新的 Person 例項。Supplier 提供了一種惰性載入物件的方式,只有在 get() 被呼叫時才建立 Person 物件。

  • Supplier<T> 是一個不接受任何引數,但會返回型別 T 的值的函式式介面。
  • 它用於延遲計算、惰性求值或者物件建立。
  • 透過呼叫 get() 方法,可以獲取由 Supplier 提供的值或物件。

Supplier 常用於需要提供值的場景,特別是在不確定何時需要這個值時,它是延遲計算的有效工具。

如果你需要一個能夠接受引數並返回結果的函式式介面,那麼應該使用 Java 8 中的另一個函式式介面,而不是 SupplierSupplier 只適用於不需要引數的場景。如果需要傳遞引數並返回結果,可以使用以下介面:

1. Function<T, R>:接收一個引數並返回一個結果

  • 定義Function<T, R> 接收一個型別為 T 的引數,並返回一個型別為 R 的結果。

示例:使用 Function 接收引數並返回結果

import java.util.function.Function;

public class FunctionExample {
    public static void main(String[] args) {
        // 定義一個 Function:接收一個字串並返回它的長度
        Function<String, Integer> lengthFunction = str -> str.length();

        // 呼叫 apply() 方法傳遞引數並獲取結果
        System.out.println(lengthFunction.apply("Hello"));  // 輸出 5
    }
}
  • T:輸入引數的型別。
  • R:返回值的型別。
  • apply(T t):方法用於接收輸入引數並返回結果。

2. BiFunction<T, U, R>:接收兩個引數並返回一個結果

  • 定義BiFunction<T, U, R> 接收兩個引數,TU,並返回一個型別為 R 的結果。

示例:使用 BiFunction 接收兩個引數並返回結果

import java.util.function.BiFunction;

public class BiFunctionExample {
    public static void main(String[] args) {
        // 定義一個 BiFunction:接收兩個整數並返回它們的乘積
        BiFunction<Integer, Integer, Integer> multiplyFunction = (a, b) -> a * b;

        // 呼叫 apply() 方法傳遞兩個引數並獲取結果
        System.out.println(multiplyFunction.apply(5, 3));  // 輸出 15
    }
}
  • T:第一個輸入引數的型別。
  • U:第二個輸入引數的型別。
  • R:返回值的型別。
  • apply(T t, U u):方法用於接收兩個輸入引數並返回結果。

3. Consumer<T>:接收一個引數但不返回結果

  • 定義Consumer<T> 接收一個型別為 T 的引數,但不返回任何結果(類似於 void 方法)。

示例:使用 Consumer 接收引數但不返回結果

import java.util.function.Consumer;

public class ConsumerExample {
    public static void main(String[] args) {
        // 定義一個 Consumer:接收一個字串並列印出來
        Consumer<String> printConsumer = str -> System.out.println(str);

        // 呼叫 accept() 方法傳遞引數
        printConsumer.accept("Hello, World!");  // 輸出 "Hello, World!"
    }
}
  • T:輸入引數的型別。
  • accept(T t):方法用於接收輸入引數,不返回結果。

4. BiConsumer<T, U>:接收兩個引數但不返回結果

  • 定義BiConsumer<T, U> 接收兩個型別的引數,但不返回結果。

示例:使用 BiConsumer 接收兩個引數但不返回結果

import java.util.function.BiConsumer;

public class BiConsumerExample {
    public static void main(String[] args) {
        // 定義一個 BiConsumer:接收兩個引數並列印
        BiConsumer<String, Integer> printConsumer = (name, age) -> 
            System.out.println(name + " is " + age + " years old");

        // 呼叫 accept() 方法傳遞兩個引數
        printConsumer.accept("Alice", 25);  // 輸出 "Alice is 25 years old"
    }
}

總結:

  • Supplier<T>:不接收任何引數,返回型別 T 的結果。
  • Function<T, R>:接收一個引數,返回型別 R 的結果。
  • BiFunction<T, U, R>:接收兩個引數,返回型別 R 的結果。
  • Consumer<T>:接收一個引數,不返回結果。
  • BiConsumer<T, U>:接收兩個引數,不返回結果。

根據需要選擇合適的函式式介面來處理帶參的場景。

相關文章