I have a question regarding CompletableFuture in Java. I'm waiting for a CompletableFuture to complete and depending on the received result, I want to either call a new task and wait for the CompletableFuture to complete or do something different. I'm not happy with my solution since there are so many callbacks and it is different to read. Could you help my to improve my code?
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");
}
});
First of all, you should avoid creating a CompletableFuture<Object>
. The generic type should be the type your function returns ( CompletableFuture<ProcessCheckResponseMessage>
in your case). That way you don't need the cast.
I would suggest using thenApply
rather than thenAccept
. This will create the second CompletableFuture for you, meaning you no longer need the declaration in the first line.
Finally, as a general rule, you should think twice about multi-line lambdas, and definitely avoid nested lambdas. You should consider creating a new method for these lambdas instead.
My 2 cents with sample code to help your callback scenario.
I wrote 3 functions: testFunction
, getResponseMessage
and getResponseString
.
testFunction
is the main function. getResponseMessage
is chained to main testFunction
through thenApply
getResponseString
is chained at the end through thenCompose
. The trick is to chain multiple smaller functions through the higher order functions like thenApply
, thenCompose
, thenCombine
etc.
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");
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.