И снова здравствуйте. В преддверии старта курса «Разработчик Java» подготовили для вас перевод полезного материала.
CompletableFuture
есть два метода, дизайн которых меня удивляет:public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
// ...
}
CompletableFuture
, возвращающих объекты разных типов.CompletableFuture
, который возвращает Void
CompletableFuture<Void>
часто используется в качестве сигнала завершения операции, однако, внеся небольшое изменение в API, этот метод можно использовать как в качестве сигнального устройства, так и в качестве носителя результатов всех завершенных операций. Давайте попробуем это сделать.CompletableFuture
и возврат CompletableFuture
, содержащего список результатов:public static <T> CompletableFuture<List<T>> allOf(
Collection<CompletableFuture<T>> futures) {
// ...
}
static CompletableFuture<Void> andTree(
CompletableFuture<?>[] cfs, int lo, int hi) {
CompletableFuture<Void> d = new CompletableFuture<Void>();
if (lo > hi) // empty
d.result = NIL;
else {
CompletableFuture<?> a, b;
int mid = (lo + hi) >>> 1;
if ((a = (lo == mid ? cfs[lo] :
andTree(cfs, lo, mid))) == null ||
(b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
andTree(cfs, mid+1, hi))) == null)
throw new NullPointerException();
if (!d.biRelay(a, b)) {
BiRelay<?,?> c = new BiRelay<>(d, a, b);
a.bipush(b, c);
c.tryFire(SYNC);
}
}
return d;
}
CompletableFuture<List<CompletableFuture<T>>> i = futures.stream()
.collect(collectingAndThen(
toList(),
l -> CompletableFuture.allOf(l.toArray(new CompletableFuture[0]))
.thenApply(__ -> l)));
CompletableFuture<List<CompletableFuture<T>
>
>
вместо CompletableFuture<Void>
, что уже хорошо. Но нам не нужен список future с результатами, нам нужен список результатов.CompletableFuture<List<T>> result = intermediate
.thenApply(list -> list.stream()
.map(CompletableFuture::join)
.collect(toList()));
public static <T> CompletableFuture<List<T>> allOf(
Collection<CompletableFuture<T>> futures) {
return futures.stream()
.collect(collectingAndThen(
toList(),
l -> CompletableFuture.allOf(l.toArray(new CompletableFuture[0]))
.thenApply(__ -> l.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList()))));
}
CompletableFuture
и завершить его вручную, после того как одна из операций вызовет исключение:CompletableFuture<List<T>> result = new CompletableFuture<>();
futures.forEach(f -> f
.handle((__, ex) -> ex == null || result.completeExceptionally(ex)));
allOf(futures).thenAccept(result::complete);
public static <T> CompletableFuture<List<T>>
allOfShortcircuiting(Collection<CompletableFuture<T>> futures) {
CompletableFuture<List<T>> result = new CompletableFuture<>();
for (CompletableFuture<?> f : futures) {
f.handle((__, ex) -> ex == null || result.completeExceptionally(ex));
}
allOf(futures).thenAccept(result::complete);
return result;
}
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
// ...
}
CompletableFuture
, содержащих объекты разных типов.CompletableFuture
, содержащий объект типа Object
.CompletableFuture#allOf
был спроектирован так, чтобы он использовался в качестве сигнального устройства. Но CompletableFuture#anyOf
не соответствует этой философии, возвращая CompletableFuture<Object>
, что еще более запутывает.CompletableFuture<Integer> f1 = CompletableFuture.completedFuture(1);
CompletableFuture<String> f2 = CompletableFuture.completedFuture("2");
Integer result = CompletableFuture.anyOf(f1, f2)
.thenApply(r -> {
if (r instanceof Integer) {
return (Integer) r;
} else if (r instanceof String) {
return Integer.valueOf((String) r);
}
throw new IllegalStateException("unexpected object type!");
}).join();
public static <T> CompletableFuture<T> anyOf(List<CompletableFuture<T>> cfs) {
return CompletableFuture.anyOf(cfs.toArray(new CompletableFuture[0]))
.thenApply(o -> (T) o);
}
public static <T> CompletableFuture<T> anyOf(CompletableFuture<T>... cfs) {
return CompletableFuture.anyOf(cfs).thenApply(o -> (T) o);
}
К сожалению, не доступен сервер mySQL