用另一个 CompletableFuture 结果完成 CompletableFuture

dbf*_*dbf 0 java asynchronous completable-future

我正在以这种方式进行异步 http 调用

public CompletableFuture<String> doPost(String path, String json) {
        CompletableFuture<String> result = new CompletableFuture<>();
        Request request = new Request.Builder().url(this.address + path).post(RequestBody.create(json, JSON)).build();
        httpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                result.completeExceptionally(new TerminationException());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                result.complete(response.body().string());
            }
        });
    }
Run Code Online (Sandbox Code Playgroud)

但响应可能包含我需要重试的代码之一,代码应该是

@Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                if (!retries.contains(responce.code()) {
                    result.complete(response.body().string());
                } else {
                    // Do retry here
                }
            }
Run Code Online (Sandbox Code Playgroud)

在重试中,我想递归调用 doPost 并使用它的返回值作为初始调用的结果。所以它返回一些可完成的未来,如何以异步方式(没有 doint .get())完成初始 CF 的结果?

谢谢。

Hol*_*ger 5

您可以使用委托,例如

public CompletableFuture<String> doPost(String path, String json) {
    CompletableFuture<String> result = new CompletableFuture<>();
    doPostImpl(this.address + path, json, result, 10);
    return result;
}

private void doPostImpl(
    String url, String json, CompletableFuture<String> result, int maxRetries) {

    Request request = new Request.Builder()
        .url(url).post(RequestBody.create(json, JSON)).build();

    httpClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(@NotNull Call call, @NotNull IOException e) {
            result.completeExceptionally(new TerminationException());
        }

        @Override
        public void onResponse(
            @NotNull Call call, @NotNull Response response) throws IOException {

            if(maxRetries <= 0 || !retries.contains(response.code())) {
                result.complete(response.body().string());
            } else {
                doPostImpl(url, json, result, maxRetries - 1);
            }
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

前端方法委托给接收目标未来的方法。重试时,实现方法会以相同的未来再次调用。因此,没有必要将结果从一个未来转移到另一个未来。


从字面上看这个问题,你可以将一个未来的结果转移到另一个使用

future2.whenComplete((value,throwable) -> {
    if(throwable != null) future1.completeExceptionally(throwable);
    else future1.complete(value);
});
Run Code Online (Sandbox Code Playgroud)

但这可能会创建一个依赖链,只要重试的次数。如上所示,没有必要这样做。