2016-11-19 146 views
1

我有一个关于Java中的CompletableFuture的问题。我正在等待CompletableFuture完成,并根据收到的结果,我想要么调用一个新任务,并等待CompletableFuture完成或做一些不同的事情。我对我的解决方案不满意,因为有太多的回调,而且它不同于阅读。你能帮我改进我的代码吗?Java 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"); 
    } 
}); 

回答

2

首先,你应该避免创建一个CompletableFuture<Object>。泛型类型应该是你函数返回的类型(你的情况为CompletableFuture<ProcessCheckResponseMessage>)。这样你就不需要演员。

我建议使用thenApply而不是thenAccept。这将为您创建第二个CompletableFuture,这意味着您不再需要第一行中的声明。

最后,作为一般规则,您应该多思考多行lambda表达式,并且绝对避免嵌套lambda表达式。您应该考虑为这些lambdas创建一个新的方法。

1

我的2美分,示例代码,以帮助您的回调情形。

我写了3个函数:testFunctiongetResponseMessagegetResponseString

  • testFunction是主要功能。
  • getResponseMessage通过thenApply
  • getResponseString链接到主testFunction在通过thenCompose端部被链接。

诀窍是链多个较小的功能通过高阶函数等thenApplythenComposethenCombine

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"); 
    } 
}