Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java CompletableFuture: Avoid callback hell

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");
  }
});
like image 907
stone Avatar asked Oct 18 '22 22:10

stone


1 Answers

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.

like image 186
Joe C Avatar answered Nov 02 '22 07:11

Joe C