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> | T | R | apply |
| Consumer | T | void | accept |
| Supplier | 無 | T | get |
| Predicate | T | boolean | test |
| BiFunction<T,U,R> | T, U | R | apply |
| UnaryOperator | T | T | apply |
| BinaryOperator | T, T | T | apply |
- 函數式介面只有一個抽象方法
- 使用
@FunctionalInterface確保正確性 java.util.function提供常用的內建介面- 搭配 Lambda 和方法參考使用