2016-11-19 148 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"); 
    } 
}