Jestem przyzwyczajony do wzoru ListenableFuture
, z wywołami zwrotnymi onSuccess()
i onFailure()
, np.Czy procedura obsługi wyjątku przekazana do klasy CompletableFuture.exceptionally() musi zwrócić znaczącą wartość?
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);
}
})
Wygląda na CompletableFuture
Java 8 jest przeznaczona do obsługi mniej więcej ten sam przypadek użycia. Naiwnie, mogę zacząć tłumaczyć powyższy przykład jako:
CompletableFuture<String> future = CompletableFuture<String>.supplyAsync(...)
.thenAccept(this::handleResult)
.exceptionally((t) -> log.error("Unexpected error", t));
Jest to z pewnością mniej gadatliwy niż wersja ListenableFuture
i wygląda bardzo obiecująco.
Jednak to nie skompilować, ponieważ exceptionally()
nie bierze Consumer<Throwable>
, to zajmuje Function<Throwable, ? extends T>
- w tym przypadku Function<Throwable, ? extends String>
.
Oznacza to, że nie można po prostu zalogować się błąd, muszę wymyślić wartości String
do zwrotu w przypadku błędu, i nie ma sensu wartość String
, aby powrócić w przypadku błędu. Mogę wrócić null
, tak aby uzyskać kod do kompilacji:
.exceptionally((t) -> {
log.error("Unexpected error", t);
return null; // hope this is ignored
});
Ale to zaczyna się rozwlekły ponownie, a poza gadatliwości, nie podoba mi się, że mając null
pływających wokół - to sugeruje, że ktoś spróbuj odzyskać lub przechwycić tę wartość, i że w pewnym momencie znacznie później mogę mieć nieoczekiwany NullPointerException
.
Jeśli exceptionally()
wziął Function<Throwable, Supplier<T>>
mogłem przynajmniej zrobić coś takiego -
.exceptionally((t) -> {
log.error("Unexpected error", t);
return() -> {
throw new IllegalStateException("why are you invoking this?");
}
});
- ale tak nie jest.
Co należy zrobić, gdy exceptionally()
nigdy nie powinno dawać prawidłowej wartości? Czy jest coś jeszcze, co mogę zrobić z CompletableFuture
lub czymś innym w nowych bibliotekach Java 8, które lepiej obsługuje ten przypadek użycia?
Pierwsza właściwie nie kompiluje, niestety, ponieważ 'log.error (...)' jest 'void' i' wyjątkowo() 'chce czegoś, co zwraca przyszły typ powrotu (w tym przypadku' String'). (Zasadniczo to doprowadziło do mojego pytania.) Dzięki za komentarze na temat płynnego API i łączenia. –
Masz rację, odpowiednio zaktualizowałem. – acelent