Java CompletableFuture:避免回调地狱
Java CompletableFuture: Avoid callback hell
我对 Java 中的 CompletableFuture 有疑问。我正在等待 CompletableFuture 完成,根据收到的结果,我想调用一个新任务并等待 CompletableFuture 完成或做一些不同的事情。我对我的解决方案不满意,因为有太多的回调并且阅读起来不一样。你能帮我改进我的代码吗?
final CompletableFuture<String> future = new CompletableFuture<>();
final ActorRef processCheckActor = actorSystem.actorOf(
springExtension.props("ProcessCheckActor"), "processCheckActor-" + new Random().nextInt());
final CompletableFuture<Object> checkResponse =
PatternsCS.ask(processCheckActor, new ProcessToCheckMessage(processId), TIMEOUT)
.toCompletableFuture();
checkResponse.thenAccept(obj -> {
final ProcessCheckResponseMessage msg = (ProcessCheckResponseMessage) obj;
if (msg.isCorrect()) {
final CompletableFuture<Object> response =
PatternsCS.ask(processSupervisorActor, new ProcessStartMessage(processId), TIMEOUT)
.toCompletableFuture();
response.thenAccept(obj2 -> {
future.complete("yes");
});
} else {
future.complete("no");
}
});
首先,你应该避免创建CompletableFuture<Object>
。通用类型应该是您的函数类型 returns (在您的情况下为 CompletableFuture<ProcessCheckResponseMessage>
)。这样你就不需要演员了。
我建议使用 thenApply
而不是 thenAccept
。这将为您创建第二个 CompletableFuture,这意味着您不再需要第一行中的声明。
最后,作为一般规则,您应该三思而后行多行 lambda,绝对避免嵌套 lambda。您应该考虑为这些 lambda 表达式创建一个新方法。
我的 2 美分示例代码可帮助您实现回调方案。
我写了 3 个函数:testFunction
、getResponseMessage
和 getResponseString
。
testFunction
是主要功能。
getResponseMessage
通过 thenApply
链接到主 testFunction
getResponseString
通过 thenCompose
链接到最后。
诀窍是通过thenApply
、thenCompose
、thenCombine
等高阶函数链接多个较小的函数
public CompletableFuture<String> testFunction() {
Future<Object> fut = Patterns.ask(getContext().actorSelection("actor1"), new ProcessToCheckMessage(1), 10);
return FutureConverters.toJava(fut).toCompletableFuture()
.thenApply(obj -> getResponseMessage(obj))
.thenCompose(processCheckResponseMessage -> getResponseString(processCheckResponseMessage));
}
public ProcessCheckResponseMessage getResponseMessage(Object obj) {
if (obj instanceof ProcessCheckResponseMessage) {
return (ProcessCheckResponseMessage) obj;
} else {
throw new RuntimeException("unexpected data");
}
}
public CompletableFuture<String> getResponseString(ProcessCheckResponseMessage processCheckResponseMessage) {
if (processCheckResponseMessage.isCorrect()) {
Future<Object> rest = Patterns.ask(getContext().actorSelection("actor2"), new ProcessStartMessage(1), 10);
return FutureConverters.toJava(rest).toCompletableFuture().thenApply(obj -> "yes");
} else {
return CompletableFuture.completedFuture("no");
}
}
我对 Java 中的 CompletableFuture 有疑问。我正在等待 CompletableFuture 完成,根据收到的结果,我想调用一个新任务并等待 CompletableFuture 完成或做一些不同的事情。我对我的解决方案不满意,因为有太多的回调并且阅读起来不一样。你能帮我改进我的代码吗?
final CompletableFuture<String> future = new CompletableFuture<>();
final ActorRef processCheckActor = actorSystem.actorOf(
springExtension.props("ProcessCheckActor"), "processCheckActor-" + new Random().nextInt());
final CompletableFuture<Object> checkResponse =
PatternsCS.ask(processCheckActor, new ProcessToCheckMessage(processId), TIMEOUT)
.toCompletableFuture();
checkResponse.thenAccept(obj -> {
final ProcessCheckResponseMessage msg = (ProcessCheckResponseMessage) obj;
if (msg.isCorrect()) {
final CompletableFuture<Object> response =
PatternsCS.ask(processSupervisorActor, new ProcessStartMessage(processId), TIMEOUT)
.toCompletableFuture();
response.thenAccept(obj2 -> {
future.complete("yes");
});
} else {
future.complete("no");
}
});
首先,你应该避免创建CompletableFuture<Object>
。通用类型应该是您的函数类型 returns (在您的情况下为 CompletableFuture<ProcessCheckResponseMessage>
)。这样你就不需要演员了。
我建议使用 thenApply
而不是 thenAccept
。这将为您创建第二个 CompletableFuture,这意味着您不再需要第一行中的声明。
最后,作为一般规则,您应该三思而后行多行 lambda,绝对避免嵌套 lambda。您应该考虑为这些 lambda 表达式创建一个新方法。
我的 2 美分示例代码可帮助您实现回调方案。
我写了 3 个函数:testFunction
、getResponseMessage
和 getResponseString
。
testFunction
是主要功能。getResponseMessage
通过thenApply
链接到主 getResponseString
通过thenCompose
链接到最后。
testFunction
诀窍是通过thenApply
、thenCompose
、thenCombine
等高阶函数链接多个较小的函数
public CompletableFuture<String> testFunction() {
Future<Object> fut = Patterns.ask(getContext().actorSelection("actor1"), new ProcessToCheckMessage(1), 10);
return FutureConverters.toJava(fut).toCompletableFuture()
.thenApply(obj -> getResponseMessage(obj))
.thenCompose(processCheckResponseMessage -> getResponseString(processCheckResponseMessage));
}
public ProcessCheckResponseMessage getResponseMessage(Object obj) {
if (obj instanceof ProcessCheckResponseMessage) {
return (ProcessCheckResponseMessage) obj;
} else {
throw new RuntimeException("unexpected data");
}
}
public CompletableFuture<String> getResponseString(ProcessCheckResponseMessage processCheckResponseMessage) {
if (processCheckResponseMessage.isCorrect()) {
Future<Object> rest = Patterns.ask(getContext().actorSelection("actor2"), new ProcessStartMessage(1), 10);
return FutureConverters.toJava(rest).toCompletableFuture().thenApply(obj -> "yes");
} else {
return CompletableFuture.completedFuture("no");
}
}