用函数式接口替代硬编码callback,核心是将变化点抽象为function、consumer等参数;统一错误处理可返回optional或completablefuture;按基础层、业务层、应用层分层封装,避免过度泛化。

用函数式接口替代硬编码的 Callback,核心是把“变化点”抽成参数,让调用方决定行为,而不是在每个地方重复写相似的回调逻辑。
把回调逻辑抽象成 Function 或 Consumer 参数
当多个地方都写类似这样的代码:
api.fetchUser(id, (user) -> { if (user != null) handleSuccess(user); else handleError(); });api.fetchOrder(orderId, (order) -> { if (order != null) showOrder(order); else showEmpty(); });
其实差异只在成功/失败后的处理动作。直接把这两个动作声明为参数即可:
- 用 Function
处理有返回值的转换(如转 DTO) - 用 Consumer
处理纯副作用(如更新 UI、打日志) - 用 BiConsumer
统一处理成功与异常分支
统一错误处理 + 默认空安全策略
团队里大量 Callback 重复做 null 判断或 try-catch,说明责任没分清。重构时可让底层 API 自动兜底:
- 返回 Optional
而非裸对象,强制调用方显式处理空值 - 用 CompletableFuture
替代回调,配合 thenApply/exceptionally分离成功失败路径 - 封装一个
SafeCallback<t></t>接口,内置空值校验和日志埋点,让业务只写核心逻辑
用 Supplier + 方法引用简化高频调用
比如登录后总要执行「刷新用户信息」+「更新本地缓存」+「通知 UI」,别每次都 new 一个匿名类:
- 定义
public interface PostLoginAction { void run(User user); } - 提供常用实现:
PostLoginAction refreshAndNotify = user -> { cache.update(user); ui.notifyLogin(user); }; - 调用时直接传方法引用:
auth.login(account, refreshAndNotify);
避免过度泛化,按场景分层封装
不是所有 Callback 都适合塞进一个万能接口。建议分三层:
-
基础层:如
Callback<t></t>只含onSuccess(T)和onError(Throwable) -
业务层:如
UserCallback继承基础层,增加onExpired()、onRateLimited()等领域语义方法 - 应用层:在 Activity/Fragment 中用 lambda 或私有方法实现具体行为,不暴露回调细节给 UI 层
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











