掌握 Java 函数式接口高级技巧:Function、Consumer、Supplier 攻略
掌握 Java 函数式接口高级技巧:Function、Consumer、Supplier 全攻略
很多开发者在使用 Function、Consumer、Supplier 时,通常停留在最基础的 map、forEach、get 上。但它们真正强大的地方,在于 函数式组合能力、延迟执行和设计模式中的应用。这些“被忽略的高级用法”可以让代码异常简洁、灵活和富有表达力。
本文将带你深入了解这三个接口的高级用法,并通过示例展示它们在实际开发中的应用场景。
1. Function<T, R>:不仅仅是 map
Function 的核心是 转换。它接受一个输入,产生一个输出。其高级用法主要围绕:
- 函数组合 (andThen / compose)
- 柯里化 (Currying)
- 策略模式中的应用
a) 函数组合 (Function Composition) - andThen & compose
这是 Function 最强大的特性。你可以将多个小的转换函数组合成一个复杂的管道,就像组装乐高积木一样。
- f.andThen(g):先执行 f,再将 f 的结果作为 g 的输入,即 g(f(x))
- f.compose(g):先执行 g,再将 g 的结果作为 f 的输入,即 f(g(x))
示例:字符串处理管道
Function<String, String> trim = String::trim;
Function<String, String> toUpperCase = String::toUpperCase;
Function<Integer, Function<String, String>> takeFirstNChars =
n -> str -> str.substring(0, Math.min(n, str.length()));
// 组合成转换管道:先trim,再转大写,最后取前5个字符
Function<String, String> cleanAndProcess = trim
.andThen(toUpperCase)
.andThen(takeFirstNChars.apply(5));
String result = cleanAndProcess.apply(" hello world "); // 输出 "HELLO"
System.out.println(result);
这种写法声明式地表达“做什么”,而非“怎么做”,代码清晰且易于维护。
b) 柯里化 (Currying)
柯里化是将一个多参数函数拆解成一系列单参数函数的技术,Function 天生支持这种方式。
// 普通二元函数
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
// 柯里化版本
Function<Integer, Function<Integer, Integer>> curriedAdd = a -> b -> a + b;
// 使用
Function<Integer, Integer> add5 = curriedAdd.apply(5);
Integer sum = add5.apply(3); // 输出 8
柯里化允许部分应用参数,创建更专用的函数,在配置、工厂方法或策略场景非常实用。
c) 策略模式 (Strategy Pattern) 应用
Function 可以直接替代传统策略接口,减少样板代码。
Function<String, Boolean> isNonEmpty = s -> s != null && !s.trim().isEmpty();
Function<String, Boolean> isEmail = s -> s != null && s.contains("@");
public void validate(String input, Function<String, Boolean> strategy) {
System.out.println(strategy.apply(input) ? "Valid" : "Invalid");
}
validate("hello", isNonEmpty); // Valid
validate("user@domain.com", isEmail); // Valid
这种方式清晰、简洁,并且易于扩展新的策略逻辑。
2. Consumer:不仅仅是 forEach
Consumer 的核心是 消费(有输入,无输出)。高级用法主要包括:
- 操作组合 (andThen)
- 异步回调
a) 操作组合 (Action Chaining)
Consumer 可以将多个消费操作串联,按顺序执行,非常适合事件处理或流水线操作。
Consumer<String> log = msg -> System.out.println("[LOG] " + msg);
Consumer<String> notify = msg -> System.out.println("[EMAIL] Notifying: " + msg);
Consumer<String> persist = msg -> System.out.println("[DB] Saving: " + msg);
Consumer<String> processCompletedOrder = log.andThen(notify).andThen(persist);
processCompletedOrder.accept("Order #12345");
输出顺序严格按照组合顺序:
[LOG] Order #12345
[EMAIL] Notifying: Order #12345
[DB] Saving: Order #12345
b) 回调函数 (Callback)
Consumer 是定义异步回调或完成钩子的理想选择。
public void downloadFile(String url, Consumer<File> onSuccess, Consumer<Exception> onError) {
new Thread(() -> {
try {
Thread.sleep(1000);
onSuccess.accept(new File("downloaded.txt"));
} catch (InterruptedException e) {
onError.accept(e);
}
}).start();
}
downloadFile(
"http://example.com/file.txt",
file -> System.out.println("File downloaded: " + file.getName()),
error -> System.err.println("Download failed: " + error.getMessage())
);
这种模式非常适合异步任务、事件通知和回调处理。
3. Supplier:不仅仅是 get()
Supplier 的核心是 提供(无输入,有输出),其高级用法在于 延迟执行、缓存和桥接方法引用。
a) 延迟执行 (Lazy Evaluation)
避免不必要的计算,仅在需要时生成结果。
logger.log(Level.DEBUG, () -> "Expensive data: " + generateExpensiveData());
这里 Supplier 确保只有在 DEBUG 级别开启时才计算字符串,节省性能开销。
b) 延迟初始化与缓存
public class ExpensiveResource {
private Supplier<ExpensiveObject> resourceSupplier = () -> createAndCacheResource();
private ExpensiveObject cachedResource;
private synchronized ExpensiveObject createAndCacheResource() {
if (cachedResource == null) {
cachedResource = new ExpensiveObject();
}
return cachedResource;
}
public ExpensiveObject getResource() {
return resourceSupplier.get();
}
}
首次调用会初始化,后续直接返回缓存,典型的 Memoization 模式。
c) 工厂模式桥接
Map<String, Supplier<Service>> serviceFactory = new HashMap<>();
serviceFactory.put("db", DatabaseService::new);
serviceFactory.put("api", ExternalApiService::new);
serviceFactory.put("mock", MockService::getInstance);
Service service = serviceFactory.get("db").get();
service.execute();
Supplier 允许你动态选择实现并延迟实例化,实现灵活解耦。
总结
接口 | 核心抽象 | 高级特性 | 典型应用场景 |
Function<T, R> | 转换 | 组合 (andThen / compose)、柯里化 | 数据管道、策略模式、转换链 |
Consumer | 消费 | 组合 (andThen) | 流水线操作、回调函数、事件监听 |
Supplier | 提供 | 延迟执行、缓存 | 延迟初始化、工厂模式、Memoization |
核心思想
- 一等公民:可传递、返回、赋值,实现行为参数化
- 无副作用 & 纯函数:便于测试和推理
- 声明式编程:描述“做什么”,而非“怎么做”,意图清晰
下次遇到复杂、多步骤的逻辑或大量样板代码时,思考如何用 Function、Consumer、Supplier 的组合来简化,通常会找到更优雅的解决方案。
相关文章
- 前端遍历数组时推荐直接for循环一把梭,少用forEach和map的原因
- Map遍历的四种方法效率对比_map遍历的几种方式和效率问题
- 用了那么久的 Java For 循环,你知道哪种方式效率最高吗?
- JS数组中 forEach() 和 map() 的区别
- 掌握 Java 函数式接口高级技巧:Function、Consumer、Supplier 攻略
- Java集合-Map_Java集合体系
- java中遍历map的几种方式_java遍历map效率高
- M3u8视频文件怎么转换成MP4?三种方法随心选!
- M3U8文件怎么转换成MP4?记住这三个转换方法就够了!
- 如何将m3u8视频转成mp4?试试这些软件