ApiFuture<V>
образует монаду над типом V
, а transform
применяет функцию к инкапсулированному значению типа V
.Если ApiFuture<V>
не содержит значение V
из-за его сбоя или отмены, преобразованное будущее будет таким же.
Если вы хотите обрабатывать сбои из-за исключений, вы можете использовать ApiFutures.catching()
вместо этого вывести альтернативный результат (например, Boolean.FALSE
).
Если вы хотите преобразовать отмену в успешное значение, я полагаю, что вам нужно было бы использовать ApiFuture.addListener
напрямую и заставить слушателя выполнить SettableApiFuture
которые вы возвращаете.Затем слушатель (который будет вызываться при отмене будущего источника) может проверить isCancelled
, чтобы обнаружить этот случай, или может перехватить и обработать CancellationException
.
Например:
/**
* Adapt an iterable of {@link ApiFuture} instances into a single {@code ApiFuture}.
*/
static <T> ApiFuture<Boolean> adaptFutures(Iterable<ApiFuture<T>> futures) {
final SettableApiFuture<Boolean> result = SettableApiFuture.create();
final ApiFuture<List<T>> allFutures = ApiFutures.allAsList(futures);
allFutures.addListener(
() -> {
if (allFutures.isCancelled()) {
result.set(Boolean.FALSE);
return;
}
try {
allFutures.get();
result.set(Boolean.TRUE);
} catch (ExecutionException | InterruptedException ex) {
// Maybe log something here?
//
// Note that InterruptedException is actually impossible here
// because we're running in the listener callback, but the API
// still marks it as potentially thrown by .get() above.
//
// So if we reach here it means that the allAsList future failed.
result.set(Boolean.FALSE);
}
},
// Not normally safe, but we know our listener runs fast enough
// to run inline on the thread that completes the last future.
Runnable::run);
return result;
}