刚看到个贴子,说一家公司裁员时,老板嫌技术总监工资太高,直接让人走人。结果总监一走,研发部门立马瘫痪,项目全停摆,最后老板只能加倍工资把人请回来。
真是典型的“只算成本,不看价值”。网友有人笑老板“自食其果”,也有人说总监该趁机涨薪。但在我看来,这件事反映的不是谁输谁赢,而是很多老板普遍的短视思维——只看眼前省下的钱,却没看到系统背后依赖的能力。
一个真正懂管理的老板,应该知道:高薪往往买的是核心竞争力。技术不是人堆砌出来的,是经验与体系的积累。
说到底,职场的本质是“价值换价值”。尊重专业,舍得投入,企业才能走得远【备注:文末可领最新资料】
算法题:转换回调函数为 Promise 函数
在公司楼下便利店蹭了杯美式,昨晚十一点多还在看日志,脑子有点糊,但这事儿得讲清楚:老项目里到处是“回调地狱”,新同学一看就头大。你要说用 Java 呢,Promise 这个词更像 JS 的,可在 Java 里我们有个等价物——CompletableFuture。把回调适配成它,代码立马顺眼,链式也好写。
为什么要“转 Promise”
场景你们肯定见过:fetchUser(id, callback)这种老式异步接口,成功走onSuccess,失败走onError,一层套一层很容易乱。而CompletableFuture有返回值,能链式拼装,还能超时、组合、并发汇聚,异常也统一处理,写起来清爽很多。
一个通用的“promisify”适配器
我先写了两个小型函数式接口,描述“如何注册回调”和“如果支持取消该怎么取消”。然后给出两个适配器:基础版和可取消版。直接贴代码,你们自己抄走用就行。
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.*;
publicclass Promisify {
// 老式回调接口
publicinterface Callback<T> {
void onSuccess(T value);
void onError(Throwable error);
}
// 仅注册回调,不支持取消
@FunctionalInterface
publicinterface CbRegister<T> {
void call(Callback<T> cb);
}
// 如果底层返回一个可取消句柄
publicinterface Cancellable { void cancel(); }
@FunctionalInterface
publicinterface CancellableRegister<T> {
Cancellable call(Callback<T> cb);
}
// 基础版:把“注册回调”的方式转成 CompletableFuture
publicstatic <T> CompletableFuture<T> promisify(CbRegister<T> register) {
CompletableFuture<T> future = new CompletableFuture<>();
try {
register.call(new Callback<T>() {
@Overridepublic void onSuccess(T value) {
future.complete(value);
}
@Overridepublic void onError(Throwable error) {
future.completeExceptionally(error);
}
});
} catch (Throwable t) {
future.completeExceptionally(t);
}
return future;
}
// 可取消版:如果底层支持 cancel,则把 future.cancel(true) 传递下去
publicstatic <T> CompletableFuture<T> promisify(CancellableRegister<T> register) {
CompletableFuture<T> future = new CompletableFuture<>();
AtomicReference<Cancellable> holder = new AtomicReference<>();
try {
Cancellable c = register.call(new Callback<T>() {
@Overridepublic void onSuccess(T value) {
future.complete(value);
}
@Overridepublic void onError(Throwable error) {
future.completeExceptionally(error);
}
});
holder.set(c);
} catch (Throwable t) {
future.completeExceptionally(t);
}
future.whenComplete((v, e) -> {
if (future.isCancelled()) {
Cancellable c = holder.get();
if (c != null) c.cancel();
}
});
return future;
}
// 小工具:给任意 future 加超时(不指定框架,纯 JDK)
publicstatic <T> CompletableFuture<T> withTimeout(
CompletableFuture<T> src, long timeout, TimeUnit unit, ScheduledExecutorService ses) {
CompletableFuture<T> wrapped = new CompletableFuture<>();
ScheduledFuture<?> timer = ses.schedule(
() -> wrapped.completeExceptionally(new TimeoutException("timeout " + timeout + " " + unit)),
timeout, unit);
src.whenComplete((v, e) -> {
if (e == null) wrapped.complete(v);
else wrapped.completeExceptionally(e);
timer.cancel(false);
});
// 取消向源头传递
wrapped.whenComplete((v, e) -> {
if (wrapped.isCancelled()) src.cancel(true);
});
return wrapped;
}
}
旧接口如何套一层就“变 Promise”
假设你手里有个老 API:
// 旧式异步:成功/失败走回调
interface LegacyUserService {
void fetchUser(String id, Promisify.Callback<User> cb);
// 或者返回可取消句柄:
Promisify.Cancellable fetchAvatar(String id, Promisify.Callback<byte[]> cb);
}
那就这么用:
LegacyUserService service = ...;
// 基础回调 -> CompletableFuture
CompletableFuture<User> userF = Promisify.promisify(cb -> service.fetchUser("42", cb));
// 可取消的回调 -> CompletableFuture
CompletableFuture<byte[]> avatarF = Promisify.promisify(cb -> service.fetchAvatar("42", cb));
// 链式写法、异常统一处理、带超时
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
CompletableFuture<String> result =
Promisify.withTimeout(userF, 2, TimeUnit.SECONDS, ses)
.thenCombine(avatarF, (u, avatar) -> u.getName() + " / " + avatar.length)
.exceptionally(e -> "兜底:" + e.getMessage());
第一,底层回调可能“多次触发”,务必保证只complete一次(CompletableFuture自己会忽略后续 complete,但你仍该查明根因)。第二,调用方取消时记得把取消往下传,不然线程池和 IO 还在干活儿,白白占资源。
行了我去热个包子。你把上面这个Promisify类丢到公共模块里,老回调世界基本就能和平演进到“类 Promise”写法了。