Si può fare in questo modo:
public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) {
CompletableFuture<SomeResult> shortCut = new CompletableFuture<>();
CompletableFuture<ResultOfFirstOp> withChain = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
// loooooong operation
if (someCondition)
withChain.complete(validValue);
else
shortCut.complete(SomeResult.RESULT_1);
});
return withChain
.thenCompose(result -> someMethodThatReturnsACompletionStage(result))
.thenApply(result ->
result.someCondition()? SomeResult.RESULT_2: SomeResult.RESULT_3)
.applyToEither(shortCut, Function.identity());
}
Invece di un CompletableFuture
creiamo due, che rappresentano i diversi percorsi di esecuzione può essere prelevata. L'operazione loooooong è presentata come eseguibile allora e completerà deliberatamente uno di questi CompletableFuture
. Le fasi successive sono concatenate allo stadio che rappresenta la condizione soddisfatta, quindi entrambi i percorsi di esecuzione si uniscono all'ultimo passaggio applyToEither(shortCut, Function.identity())
.
Il futuro shortCut
ha già il tipo del risultato finale e sarà completata con la RESULT_1
, il risultato della vostra null
percorso che passa, che farà sì che il completamento immediato di tutta l'operazione. Se non ti piace la dipendenza tra il primo stadio ed il valore del risultato effettivo della scorciatoia è possibile allontanare in questo modo:
public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) {
CompletableFuture<Object> shortCut = new CompletableFuture<>();
CompletableFuture<ResultOfFirstOp> withChain = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
// loooooong operation
if (someCondition)
withChain.complete(validValue);
else
shortCut.complete(null);
});
return withChain
.thenCompose(result -> someMethodThatReturnsACompletionStage(result))
.thenApply(result ->
result.someCondition()? SomeResult.RESULT_2: SomeResult.RESULT_3)
.applyToEither(shortCut.thenApply(x -> SomeResult.RESULT_1), Function.identity());
}
Se il terzo passo non è stata esemplare, ma sembra esattamente mostrato in questione, è possibile unire con il passo percorso di codice giunzione:
public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) {
CompletableFuture<ResultOfSecondOp> shortCut = new CompletableFuture<>();
CompletableFuture<ResultOfFirstOp> withChain = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
// loooooong operation
if (someCondition)
withChain.complete(validValue);
else
shortCut.complete(null);
});
return withChain
.thenCompose(result -> someMethodThatReturnsACompletionStage(result))
.applyToEither(shortCut, result -> result==null? SomeResult.RESULT_1:
result.someCondition()? SomeResult.RESULT_2: SomeResult.RESULT_3);
}
allora abbiamo solo saltare il secondo passaggio, il someMethodThatReturnsACompletionStage
invocazione, ma che può ancora riposare per una lunga catena di passaggi intermedi, tutti i saltati senza la necessità di eseguire un salto manuale tramite nullcheck.
Funziona, grazie! Seguendo lo stesso schema (creando diversi 'CompletableFuture' e usando' applyToEither (...) ') allora potrebbe essere possibile estenderlo a più percorsi, giusto? – Pelocho
Sì, è possibile estenderlo a più percorsi, ma occorre fare attenzione a mantenere il codice risultante gestibile. Forse aiuta a incapsulare la logica di un ramo in un metodo di utilità che puoi usare più volte. – Holger