JAVA中的函數介面,你都用過嗎

2023-11-19 15:00:21

公眾號「架構成長指南」,專注於生產實踐、雲原生、分散式系統、巨量資料技術分享。

在這篇文章中,我們將通過範例來學習 Java 函數式介面。

函數式介面的特點

  1. 只包含一個抽象方法的介面稱為函數式介面。
  2. 它可以有任意數量的預設靜態方法,但只能包含一個抽象方法。它還可以宣告物件類的方法。
  3. 函數介面也稱為單一抽象方法介面或SAM 介面。
  4. 函數式介面只有在沒有任何抽象方法時才可以擴充套件另一個介面。
  5. Java API 具有許多單方法介面,例如 Runnable、Callable、Comparator、ActionListener等。它們可以使用匿名類語法來實現和範例化。

介面範例

建立一個自定義的Sayable介面,這是一個使用@FunctionalInterface註解的函數式介面。
@FunctionalInterface註解表示該介面是一個函數式介面,並且只包含一個抽象方法。

自定義函數介面範例

@FunctionalInterface  
interface Sayable{  
    void say(String msg);   // abstract method   
}  

讓我們通過main()方法來演示一個自定義的函數式介面。我們使用Lambda表示式來實現函數式介面。

public class FunctionalInterfacesExample {

    public static void main(String[] args) {

        Sayable sayable = (msg) -> {
            System.out.println(msg);
        };
        sayable.say("Say something ..");
    }
}

Predefined 函數介面

Java提供了Predefined的函數式介面,通過使用 lambda 和方法參照來處理常式式程式設計。

Predicate是檢查條件的函數,它接受一個引數並返回boolean結果。

讓我們來看一下Predicate介面的內部實現。

import java.util.function.Predicate;

public interface Predicate<T> {
    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {
        // 預設方法的實現
        return (t) -> test(t) && other.test(t);
    }

    // 其他預設方法和靜態方法...
}

Predicate介面只包含一個抽象方法test(T t)同時它還包含預設方法和靜態方法。

讓我們建立一個範例來演示Predicate函數式介面的用法:

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // 使用Predicate介面檢查數位是否為偶數
        Predicate<Integer> evenNumberPredicate = number -> number % 2 == 0;
        System.out.println("Even numbers:");
        printNumbers(numbers, evenNumberPredicate);

        // 使用Predicate介面檢查數位是否大於5
        Predicate<Integer> greaterThanFivePredicate = number -> number > 5;
        System.out.println("Numbers greater than 5:");
        printNumbers(numbers, greaterThanFivePredicate);
    }

    public static void printNumbers(List<Integer> numbers, Predicate<Integer> predicate) {
        for (Integer number : numbers) {
            if (predicate.test(number)) {
                System.out.println(number);
            }
        }
    }
}

Function 函數介面

Function函數介面是Java中的一個函數式介面,它定義了一個接收一個引數並返回結果的函數。它的定義如下:

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

Function介面有兩個泛型引數:T表示輸入引數的型別,R表示返回結果的型別。它包含一個抽象方法apply(),接收一個型別為T的引數,並返回一個型別為R的結果。

Function介面常用於將一個值轉換為另一個值,或者對輸入值進行處理和計算。它可以被用於各種場景,如資料轉換、對映、計算和處理等。

以下是一個使用Function函數介面的範例:

import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        // 建立一個Function介面來將字串轉換為大寫
        Function<String, String> uppercaseFunction = str -> str.toUpperCase();

        // 使用Function介面將字串轉換為大寫
        String result = uppercaseFunction.apply("hello world");
        System.out.println(result);  // 輸出: HELLO WORLD

        // 使用Function介面將字串轉換為其長度
        Function<String, Integer> lengthFunction = str -> str.length();
        int length = lengthFunction.apply("hello");
        System.out.println(length);  // 輸出: 5
    }
}

Supplier 函數介面

Supplier用於表示一個提供(供應)結果的函數。它通常用於延遲計算或在需要時生成值。通過呼叫get()方法,我們可以獲取由Supplier範例提供的結果。

以下是Consumer介面的實現

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

由於Supplier介面只有一個抽象方法,因此可以使用lambda表示式快速建立Supplier範例。下面是一個範例:

import java.util.Random;
import java.util.function.Supplier;

public class Main {
    public static void main(String[] args) {
        // 建立一個Supplier介面來生成隨機整數
        Supplier<Integer> randomIntegerSupplier = () -> new Random().nextInt();

        // 使用Supplier介面生成隨機整數
        int randomNumber = randomIntegerSupplier.get();
        System.out.println(randomNumber);

        // 建立一個Supplier介面來生成當前時間戳
        Supplier<Long> timestampSupplier = () -> System.currentTimeMillis();

        // 使用Supplier介面生成當前時間戳
        long timestamp = timestampSupplier.get();
        System.out.println(timestamp);
    }
}

Consumer 函數介面

Consumer用於表示接受一個引數並執行某些操作的函數。它定義了一個名為accept(T t)的抽象方法,接受一個引數,並且沒有返回值。

以下是Consumer介面的簡化版本

@FunctionalInterface
public interface Consumer<T> {
    void accept(T arg0);
}

Consumer介面適用於那些需要對傳入的引數進行某種操作,而不需要返回結果的情況。它可以用於在不同的上下文中執行各種操作,如列印、修改狀態、更新物件等。
下面是一個使用Consumer介面的範例:

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Dave");

        // 使用Consumer介面列印每個名字
        Consumer<String> printName = name -> System.out.println(name);
        names.forEach(printName);

        // 使用Consumer介面修改每個名字為大寫形式
        Consumer<String> uppercaseName = name -> {
            String uppercase = name.toUpperCase();
            System.out.println(uppercase);
        };
        names.forEach(uppercaseName);
    }
}

在上述範例中,我們建立了兩個Consumer介面的範例。第一個printName用於列印每個名字,第二個uppercaseName用於將每個名字轉換為大寫形式並列印。

通過呼叫forEach()方法並傳入相應的Consumer介面範例,我們可以對列表中的每個元素執行相應的操作。在範例中,我們對名字列表中的每個名字進行了列印和轉換操作。

Consumer介面的使用場景包括遍歷集合、處理回撥函數、更新物件狀態等。它提供了一種簡潔的方式來執行鍼對輸入引數的操作,使得程式碼更加清晰和模組化。

BiFunction 函數介面

BiFunction函數式介面表示接受兩個引數並返回結果的函數。它定義了一個名為apply(T t, U u)的抽象方法,接受兩個引數,並返回一個結果。

讓我們來看一下BiFunction介面的簡化版本。

@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T arg0, U arg1);
}

BiFunction介面適用於那些需要接受兩個輸入引數併產生結果的情況。它可以用於執行各種操作,如計算、轉換、篩選等。
下面是一個使用BiFunction介面的範例:

import java.util.function.BiFunction;

public class Main {
    public static void main(String[] args) {
        // 使用BiFunction介面計算兩個數的和
        BiFunction<Integer, Integer, Integer> sumFunction = (a, b) -> a + b;
        int sum = sumFunction.apply(5, 3);
        System.out.println(sum);  // 輸出: 8

        // 使用BiFunction介面將兩個字串拼接起來
        BiFunction<String, String, String> concatenateFunction = (str1, str2) -> str1 + str2;
        String result = concatenateFunction.apply("Hello, ", "World!");
        System.out.println(result);  // 輸出: Hello, World!
    }
}

BiConsumer函數介面

BiConsumer介面,用於表示接受兩個引數並執行某些操作的函數。它定義了一個名為accept(T t, U u)的抽象方法,接受兩個引數,並且沒有返回值。

以下是BiConsumer介面的簡化版本:

import java.util.function.BiConsumer;

@FunctionalInterface
public interface BiConsumer<T, U> {
    void accept(T t, U u);
}

BiConsumer介面適用於那些需要對傳入的兩個引數進行某種操作,而不需要返回結果的情況。它可以用於在不同的上下文中執行各種操作,如列印、修改狀態、更新物件等。
下面是一個使用BiConsumer介面的範例:

import java.util.function.BiConsumer;

public class Main {
    public static void main(String[] args) {
        // 使用BiConsumer介面列印兩個數的和
        BiConsumer<Integer, Integer> sumPrinter = (a, b) -> System.out.println(a + b);
        sumPrinter.accept(5, 3);

        // 使用BiConsumer介面列印兩個字串的拼接結果
        BiConsumer<String, String> concatenationPrinter = (str1, str2) -> System.out.println(str1 + str2);
        concatenationPrinter.accept("Hello, ", "World!");
    }
}
那些庫或中介軟體再用BiConsumer

BiPredicate 函數介面

BiPredicate介面用於表示接受兩個引數並返回一個布林值的函數。它定義了一個名為test(T t, U u)的抽象方法,接受兩個引數,並返回一個布林值。

以下是BiPredicate介面的簡化版本:

@FunctionalInterface 
public interface BiPredicate<T, U> {
     boolean test(T t, U u);
     // Default methods are defined also
}

BiPredicate介面適用於那些需要對傳入的兩個引數進行某種條件判斷,並返回布林值的情況。它可以用於執行各種條件判斷,如相等性比較、大小比較、複雜條件判斷等。

下面是一個使用BiPredicate介面的範例:

import java.util.function.BiPredicate;

public class Main {
    public static void main(String[] args) {
        // 使用BiPredicate介面判斷兩個數是否相等
        BiPredicate<Integer, Integer> equalityPredicate = (a, b) -> a.equals(b);
        boolean isEqual = equalityPredicate.test(5, 5);
        System.out.println(isEqual);  // 輸出: true

        // 使用BiPredicate介面判斷一個字串是否包含另一個字串
        BiPredicate<String, String> containsPredicate = (str1, str2) -> str1.contains(str2);
        boolean isContains = containsPredicate.test("Hello, World!", "World");
        System.out.println(isContains);  // 輸出: true
    }
}