Есть ли в Java конвертер из списка <CompletionStage>в CompletionStage <List>? - PullRequest
0 голосов
/ 14 мая 2019

Как в этом гипотетическом примере использования of:

List<CompletionStage<Long>> listOfFutureLongs = getFutureLongs(...)
CompletionStage<List<Long>> futureListOfLongs = CompletionStage.of(listOfFutureLongs)

Ответы [ 2 ]

1 голос
/ 15 мая 2019

Интернет говорит, используйте завершаемое будущее:

List<CompletionStage<Long>> futureLongs = getFutureLongs();
var arr = futureLongs.toArray(new CompletableFuture[futureLongs.size()]);
CompletionStage<List<Long>> result = CompletableFuture.allOf(arr)
  .thenApply(unused -> futureLongs.stream().map(f -> f.toCompletableFuture().join()).collect(Collectors.toList()));
1 голос
/ 14 мая 2019

Странно нет.

Есть CompletableFuture.allOf для CompletableFuture, что похоже на то, что вы хотите, но нет аналогичной функции для CompletionStage.

Вы можете использовать CompletionStage.toCompletableFuture, чтобы получить фьючерс, или вы можете написать свой собственный.

К сожалению, неспособность проверить CompletionStage, чтобы убедиться, что это уже сделано, означает, что вы не можете сделать это столь же эффективно.

Этот код находится в моем еще не выпущенном (также еще не протестированном) проекте с открытым исходным кодом.Не стесняйтесь использовать его:

public static <T> CompletionStage<List<T>> list(List<CompletionStage<T>> list)
{
    if (list.size() <= 0)
    {
        return CompletableFuture.completedFuture(Collections.emptyList());
    }
    if (list.size() == 1)
    {
        return list.get(0).thenApply(Collections::singletonList);
    }
    final AtomicInteger waiters = new AtomicInteger(1);
    final List<T> ret = new ArrayList<>(list.size());
    final AtomicReference<Throwable> retErr = new AtomicReference<>();
    final CompletableFuture<List<T>> retFuture = new CompletableFuture<>();
    for (int i = 0; i < list.size(); ++i)
    {
        ret.add(null);
        final int pos = i;
        final CompletionStage<T> cs = list.get(i);
        if (cs == null)
        {
            continue;
        }
        waiters.incrementAndGet();
        cs.whenComplete((val, err) -> {
            if (err != null)
            {
                retErr.compareAndSet(null, err);
            }
            ret.set(pos, val);
            _doneListItem(waiters, retFuture, ret, retErr.get());
        });
    }
    _doneListItem(waiters, retFuture, ret, retErr.get());
    return retFuture;
}

private static <T> void _doneListItem(AtomicInteger waitCount, CompletableFuture<List<T>> ret, List<T> val, Throwable err)
{
    if (waitCount.decrementAndGet() == 0)
    {
        if (err != null)
        {
            ret.completeExceptionally(err);
        }
        else
        {
            ret.complete(val);
        }
    }
}
...