Java 內建函數式介面
Java 8 在 java.util.function 套件中提供了許多常用的函數式介面。
四大核心介面
| 介面 | 方法 | 參數 | 回傳 | 用途 |
|---|---|---|---|---|
Function<T,R> | apply(T) | T | R | 轉換 |
Consumer<T> | accept(T) | T | void | 消費 |
Supplier<T> | get() | 無 | T | 提供 |
Predicate<T> | test(T) | T | boolean | 判斷 |
Function
轉換型別或處理資料:
import java.util.function.Function;
// 基本用法
Function<String, Integer> length = s -> s.length();
int len = length.apply("Hello"); // 5
// 方法參考
Function<String, Integer> length2 = String::length;
// 實際應用
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> lengths = names.stream()
.map(String::length)
.collect(Collectors.toList()); // [5, 3, 7]
組合 Function
Function<String, String> trim = String::trim;
Function<String, String> upper = String::toUpperCase;
// andThen:先執行 trim,再執行 upper
Function<String, String> combined = trim.andThen(upper);
combined.apply(" hello "); // "HELLO"
// compose:先執行 upper,再執行 trim
Function<String, String> combined2 = trim.compose(upper);
combined2.apply(" hello "); // " HELLO "
Consumer
消費資料,不回傳結果:
import java.util.function.Consumer;
// 基本用法
Consumer<String> printer = s -> System.out.println(s);
printer.accept("Hello"); // 印出 "Hello"
// 方法參考
Consumer<String> printer2 = System.out::println;
// 實際應用
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(System.out::println);
組合 Consumer
Consumer<String> log = s -> System.out.println("[LOG] " + s);
Consumer<String> save = s -> database.save(s);
// andThen:依序執行
Consumer<String> combined = log.andThen(save);
combined.accept("data"); // 先 log,再 save
Supplier
提供資料,不需要輸入:
import java.util.function.Supplier;
// 基本用法
Supplier<String> greeting = () -> "Hello, World!";
String s = greeting.get(); // "Hello, World!"
// 工廠模式
Supplier<List<String>> listFactory = ArrayList::new;
List<String> list = listFactory.get();
// 延遲計算
Supplier<Double> randomSupplier = Math::random;
double value = randomSupplier.get(); // 每次呼叫才計算
// 實際應用:Optional 的 orElseGet
Optional<String> opt = Optional.empty();
String value = opt.orElseGet(() -> computeDefault());
Predicate
判斷條件,回傳 boolean:
import java.util.function.Predicate;
// 基本用法
Predicate<String> isEmpty = s -> s.isEmpty();
boolean result = isEmpty.test(""); // true
// 方法參考
Predicate<String> isEmpty2 = String::isEmpty;
// 實際應用
List<String> names = Arrays.asList("Alice", "Bob", "", "Charlie");
List<String> nonEmpty = names.stream()
.filter(s -> !s.isEmpty())
.collect(Collectors.toList()); // ["Alice", "Bob", "Charlie"]
組合 Predicate
Predicate<String> notEmpty = s -> !s.isEmpty();
Predicate<String> longerThan3 = s -> s.length() > 3;
// and
Predicate<String> combined = notEmpty.and(longerThan3);
combined.test("Hello"); // true
combined.test("Hi"); // false
// or
Predicate<String> either = notEmpty.or(longerThan3);
// negate
Predicate<String> empty = notEmpty.negate();
BiFunction
接受兩個參數:
import java.util.function.BiFunction;
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
int sum = add.apply(3, 5); // 8
BiFunction<String, String, String> concat = (a, b) -> a + b;
String result = concat.apply("Hello", "World"); // "HelloWorld"
// Map 的 computeIfAbsent
Map<String, Integer> map = new HashMap<>();
map.computeIfAbsent("key", k -> k.length());
BiConsumer
接受兩個參數,無回傳:
import java.util.function.BiConsumer;
BiConsumer<String, Integer> printer = (name, age) ->
System.out.println(name + " is " + age);
printer.accept("Alice", 25); // "Alice is 25"
// Map 的 forEach
Map<String, Integer> map = Map.of("Alice", 25, "Bob", 30);
map.forEach((k, v) -> System.out.println(k + ": " + v));
BiPredicate
接受兩個參數,回傳 boolean:
import java.util.function.BiPredicate;
BiPredicate<String, Integer> lengthCheck = (s, len) -> s.length() == len;
boolean result = lengthCheck.test("Hello", 5); // true
UnaryOperator
輸入和輸出同型別:
import java.util.function.UnaryOperator;
// UnaryOperator<T> 繼承自 Function<T, T>
UnaryOperator<String> toUpper = String::toUpperCase;
String result = toUpper.apply("hello"); // "HELLO"
UnaryOperator<Integer> square = x -> x * x;
int result2 = square.apply(5); // 25
// List 的 replaceAll
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.replaceAll(String::toUpperCase); // ["A", "B", "C"]
BinaryOperator
兩個相同型別的輸入,輸出同型別:
import java.util.function.BinaryOperator;
// BinaryOperator<T> 繼承自 BiFunction<T, T, T>
BinaryOperator<Integer> add = (a, b) -> a + b;
int sum = add.apply(3, 5); // 8
BinaryOperator<String> concat = (a, b) -> a + b;
// Stream 的 reduce
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(0, (a, b) -> a + b); // 15
// 靜態方法
BinaryOperator<Integer> max = BinaryOperator.maxBy(Comparator.naturalOrder());
BinaryOperator<Integer> min = BinaryOperator.minBy(Comparator.naturalOrder());
基本型別特化
避免自動裝箱的效能損失:
// int
IntFunction<String> intToString = i -> String.valueOf(i);
IntConsumer printer = System.out::println;
IntSupplier random = () -> (int)(Math.random() * 100);
IntPredicate isPositive = i -> i > 0;
IntUnaryOperator square = i -> i * i;
IntBinaryOperator add = (a, b) -> a + b;
// long
LongFunction<String> longToString = l -> String.valueOf(l);
LongConsumer longPrinter = System.out::println;
// double
DoubleFunction<String> doubleToString = d -> String.valueOf(d);
DoubleConsumer doublePrinter = System.out::println;
// 轉換
IntToLongFunction intToLong = i -> (long) i;
IntToDoubleFunction intToDouble = i -> (double) i;
ToIntFunction<String> strToInt = Integer::parseInt;
ToLongFunction<String> strToLong = Long::parseLong;
ToDoubleFunction<String> strToDouble = Double::parseDouble;
實際範例
驗證器
public class Validator<T> {
private final List<Predicate<T>> rules = new ArrayList<>();
public Validator<T> addRule(Predicate<T> rule) {
rules.add(rule);
return this;
}
public boolean validate(T value) {
return rules.stream().allMatch(rule -> rule.test(value));
}
}
// 使用
Validator<String> passwordValidator = new Validator<String>()
.addRule(s -> s.length() >= 8)
.addRule(s -> s.matches(".*[A-Z].*"))
.addRule(s -> s.matches(".*[0-9].*"));
boolean valid = passwordValidator.validate("Password123"); // true
策略模式
public class PriceCalculator {
private final Map<String, Function<Double, Double>> strategies = new HashMap<>();
public PriceCalculator() {
strategies.put("normal", price -> price);
strategies.put("vip", price -> price * 0.8);
strategies.put("svip", price -> price * 0.6);
}
public double calculate(String type, double price) {
return strategies.getOrDefault(type, p -> p).apply(price);
}
}
事件處理
public class EventBus {
private final Map<String, List<Consumer<Object>>> listeners = new HashMap<>();
public void subscribe(String event, Consumer<Object> handler) {
listeners.computeIfAbsent(event, k -> new ArrayList<>()).add(handler);
}
public void publish(String event, Object data) {
List<Consumer<Object>> handlers = listeners.get(event);
if (handlers != null) {
handlers.forEach(h -> h.accept(data));
}
}
}
介面總覽
| 介面 | 參數 | 回傳 | 方法 |
|---|---|---|---|
Function<T,R> | T | R | apply |
BiFunction<T,U,R> | T, U | R | apply |
Consumer<T> | T | void | accept |
BiConsumer<T,U> | T, U | void | accept |
Supplier<T> | 無 | T | get |
Predicate<T> | T | boolean | test |
BiPredicate<T,U> | T, U | boolean | test |
UnaryOperator<T> | T | T | apply |
BinaryOperator<T> | T, T | T | apply |
重點整理
Function:轉換,T → RConsumer:消費,T → voidSupplier:提供,() → TPredicate:判斷,T → boolean- 使用
andThen、compose組合 Function - 使用
and、or、negate組合 Predicate - 基本型別特化版本避免裝箱開銷