2016-11-19 3 views
1

У меня есть вопрос относительно CompletableFuture в Java. Я жду завершения CompletableFuture и в зависимости от полученного результата, я хочу либо вызвать новую задачу, либо дождаться завершения CompletingFuture или сделать что-то другое. Я не доволен своим решением, так как так много обратных вызовов, и читать их не так. Не могли бы вы помочь мне улучшить мой код?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 для вас, то есть вам больше не нужно объявление в первой строке.

Наконец, как правило, вы должны подумать дважды о многострочных лямбдах и, безусловно, избегать вложенных лямбда. Вы должны рассмотреть возможность создания нового метода для этих лямбда.

1

Мои 2 цента с образцом кода, чтобы помочь вашему сценарию обратного вызова.

Я написал 3 функции: testFunction, getResponseMessage и getResponseString.

  • testFunction - основная функция.
  • getResponseMessage прикован к основному testFunction через thenApply
  • 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"); 
    } 
}