Java 函數式介面 (Functional Interface)

函數式介面是只有一個抽象方法的介面,可以使用 Lambda 表達式來實作。Java 8 在 java.util.function 套件提供了許多內建的函數式介面。

@FunctionalInterface 註解

@FunctionalInterface
public interface Calculator {
    int calculate(int a, int b);

    // 可以有 default 方法
    default void print() {
        System.out.println("Calculator");
    }

    // 可以有 static 方法
    static void info() {
        System.out.println("Info");
    }
}

// 使用 Lambda 實作
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;

System.out.println(add.calculate(3, 4));       // 7
System.out.println(multiply.calculate(3, 4));  // 12

內建函數式介面

Function<T, R>

接受一個參數,回傳一個結果。

import java.util.function.Function;

Function<String, Integer> strLength = s -> s.length();
System.out.println(strLength.apply("Hello"));  // 5

// 組合函數
Function<Integer, Integer> doubleIt = n -> n * 2;
Function<Integer, Integer> addTen = n -> n + 10;

Function<Integer, Integer> combined = doubleIt.andThen(addTen);
System.out.println(combined.apply(5));  // 20(5*2+10)

Function<Integer, Integer> composed = doubleIt.compose(addTen);
System.out.println(composed.apply(5));  // 30((5+10)*2)

Consumer

接受一個參數,不回傳結果。

import java.util.function.Consumer;

Consumer<String> printer = s -> System.out.println(s);
printer.accept("Hello");  // Hello

// 鏈式調用
Consumer<String> upper = s -> System.out.println(s.toUpperCase());
printer.andThen(upper).accept("hello");
// hello
// HELLO

Supplier

不接受參數,回傳一個結果。

import java.util.function.Supplier;

Supplier<Double> randomNum = () -> Math.random();
System.out.println(randomNum.get());  // 0.xxx

Supplier<List<String>> listSupplier = ArrayList::new;
List<String> list = listSupplier.get();

Predicate

接受一個參數,回傳 boolean。

import java.util.function.Predicate;

Predicate<Integer> isPositive = n -> n > 0;
System.out.println(isPositive.test(5));   // true
System.out.println(isPositive.test(-3));  // false

// 組合
Predicate<Integer> isEven = n -> n % 2 == 0;
Predicate<Integer> isPositiveEven = isPositive.and(isEven);
System.out.println(isPositiveEven.test(4));  // true
System.out.println(isPositiveEven.test(3));  // false

// 否定
Predicate<Integer> isNotPositive = isPositive.negate();

BiFunction<T, U, R>

接受兩個參數,回傳一個結果。

import java.util.function.BiFunction;

BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
System.out.println(add.apply(3, 4));  // 7

BiFunction<String, String, String> concat = (a, b) -> a + b;
System.out.println(concat.apply("Hello", " World"));  // Hello World

UnaryOperator 和 BinaryOperator

import java.util.function.UnaryOperator;
import java.util.function.BinaryOperator;

// UnaryOperator:輸入輸出同類型
UnaryOperator<Integer> square = n -> n * n;
System.out.println(square.apply(5));  // 25

// BinaryOperator:兩個輸入一個輸出,同類型
BinaryOperator<Integer> max = (a, b) -> a > b ? a : b;
System.out.println(max.apply(3, 7));  // 7

基本型別的函數式介面

為避免自動裝箱/拆箱的效能損耗:

import java.util.function.*;

// int 專用
IntFunction<String> intToStr = n -> "Number: " + n;
IntConsumer printInt = n -> System.out.println(n);
IntSupplier getInt = () -> 42;
IntPredicate isEven = n -> n % 2 == 0;
IntUnaryOperator doubleInt = n -> n * 2;
IntBinaryOperator addInts = (a, b) -> a + b;

// 類似的還有 Long、Double 版本
LongFunction<String> longToStr = n -> "Long: " + n;
DoubleFunction<String> doubleToStr = n -> "Double: " + n;

// 轉換型別
IntToDoubleFunction intToDouble = n -> n * 1.5;
DoubleToIntFunction doubleToInt = d -> (int) d;

在 Stream 中使用

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// Function - map
List<Integer> lengths = names.stream()
    .map(String::length)  // Function<String, Integer>
    .collect(Collectors.toList());

// Predicate - filter
List<String> longNames = names.stream()
    .filter(s -> s.length() > 3)  // Predicate<String>
    .collect(Collectors.toList());

// Consumer - forEach
names.stream()
    .forEach(System.out::println);  // Consumer<String>

// Supplier - generate
Stream.generate(() -> "Hello")  // Supplier<String>
    .limit(3)
    .forEach(System.out::println);

自訂函數式介面

@FunctionalInterface
interface TriFunction<T, U, V, R> {
    R apply(T t, U u, V v);
}

TriFunction<Integer, Integer, Integer, Integer> sum = (a, b, c) -> a + b + c;
System.out.println(sum.apply(1, 2, 3));  // 6

重點整理

介面參數回傳方法
Function<T,R>TRapply
ConsumerTvoidaccept
SupplierTget
PredicateTbooleantest
BiFunction<T,U,R>T, URapply
UnaryOperatorTTapply
BinaryOperatorT, TTapply
  • 函數式介面只有一個抽象方法
  • 使用 @FunctionalInterface 確保正確性
  • java.util.function 提供常用的內建介面
  • 搭配 Lambda 和方法參考使用