Sono abituato allo schema ListenableFuture
, con le chiamate onSuccess()
e onFailure()
, ad es.Un gestore di eccezioni è passato a CompletableFuture.exceptionally() deve restituire un valore significativo?
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
ListenableFuture<String> future = service.submit(...)
Futures.addCallback(future, new FutureCallback<String>() {
public void onSuccess(String result) {
handleResult(result);
}
public void onFailure(Throwable t) {
log.error("Unexpected error", t);
}
})
Sembra Java 8 di CompletableFuture
ha lo scopo di gestire più o meno lo stesso caso d'uso. Ingenuamente, ho potuto iniziare a tradurre l'esempio precedente come:
CompletableFuture<String> future = CompletableFuture<String>.supplyAsync(...)
.thenAccept(this::handleResult)
.exceptionally((t) -> log.error("Unexpected error", t));
Questo è certamente meno prolisso rispetto alla versione ListenableFuture
e sembra molto promettente.
Tuttavia, non si compila, perché exceptionally()
non ci vuole un Consumer<Throwable>
, ci vuole un Function<Throwable, ? extends T>
- in questo caso, un Function<Throwable, ? extends String>
.
Ciò significa che non posso semplicemente registrare l'errore, devo trovare un valore String
da restituire nel caso dell'errore, e non c'è un valore significativo String
da restituire nel caso dell'errore. Posso tornare null
, solo per ottenere il codice per compilare:
.exceptionally((t) -> {
log.error("Unexpected error", t);
return null; // hope this is ignored
});
Ma questo sta iniziando a farsi verbose di nuovo, e al di là di dettaglio, non mi piace avere quel null
galleggia intorno - suggerisce che qualcuno potrebbe prova a recuperare o catturare quel valore, e che a un certo punto molto più tardi potrei avere un inaspettato NullPointerException
.
Se exceptionally()
preso un Function<Throwable, Supplier<T>>
ho potuto almeno fare qualcosa di simile -
.exceptionally((t) -> {
log.error("Unexpected error", t);
return() -> {
throw new IllegalStateException("why are you invoking this?");
}
});
- ma non è così.
Qual è la cosa giusta da fare quando exceptionally()
non dovrebbe mai produrre un valore valido? C'è qualcos'altro che posso fare con CompletableFuture
, o qualcos'altro nelle nuove librerie Java 8, che meglio supporta questo caso d'uso?
Il primo in realtà non viene compilato, sfortunatamente, perché 'log.error (...)' è 'void' e' eccezionalmente() 'vuole qualcosa che restituisce il tipo di ritorno del futuro (in questo caso un' String'). (Che è fondamentalmente ciò che ha portato alla mia domanda.) Grazie per i commenti sull'API fluente e concatenamento, però. –
Hai ragione, mi sono aggiornato di conseguenza. – acelent