У меня есть асинхронный API, который по существу возвращает результаты через нумерацию страниц
public CompletableFuture<Response> getNext(int startFrom);
Каждый объект Response
содержит список смещений от startFrom
и флаг, указывающий, остались ли еще элементы, и, следовательно, еще один getNext()
запрос на выполнение.
Я хотел бы написать метод, который просматривает все страницы и извлекает все смещения. Я могу написать это синхронно, вот так
int startFrom = 0;
List<Integer> offsets = new ArrayList<>();
for (;;) {
CompletableFuture<Response> future = getNext(startFrom);
Response response = future.get(); // an exception stops everything
if (response.getOffsets().isEmpty()) {
break; // we're done
}
offsets.addAll(response.getOffsets());
if (!response.hasMore()) {
break; // we're done
}
startFrom = getLast(response.getOffsets());
}
Другими словами, мы вызываем getNext()
с startFrom
в 0. Если выдается исключение, мы закорачиваем весь процесс. В противном случае, если нет смещений, мы завершаем. Если есть смещения, мы добавляем их в основной список. Если больше не осталось извлечь, мы завершаем. В противном случае мы сбрасываем startFrom
до последнего смещения, которое мы получили, и повторяем.
В идеале я хочу сделать это без блокировки с помощью CompletableFuture::get()
и возврата CompletableFuture<List<Integer>>
, содержащего все смещения.
Как я могу это сделать? Как я могу составить фьючерсы, чтобы собрать их результаты?
Я думаю о "рекурсивном" (на самом деле не в исполнении, а в коде)
private CompletableFuture<List<Integer>> recur(int startFrom, List<Integer> offsets) {
CompletableFuture<Response> future = getNext(startFrom);
return future.thenCompose((response) -> {
if (response.getOffsets().isEmpty()) {
return CompletableFuture.completedFuture(offsets);
}
offsets.addAll(response.getOffsets());
if (!response.hasMore()) {
return CompletableFuture.completedFuture(offsets);
}
return recur(getLast(response.getOffsets()), offsets);
});
}
public CompletableFuture<List<Integer>> getAll() {
List<Integer> offsets = new ArrayList<>();
return recur(0, offsets);
}
Мне это не нравится, с точки зрения сложности. Можем ли мы сделать лучше?