引用 CompletableFuture 中的字段,它又可以是 CompletableFuture :java

reference to a field inside a CompletableFuture which can again be a CompletableFuture : java

我正在调用一个返回 CompletableFuture 的服务。

输出结构如下。

Class Output {
    public String name;
    public Integer age;
}

我想调用服务,并想继续执行直到名字出现。

有点像,

CompletableFuture<Output> futureOutput = makeServiceCall(input);
String name = futureOutput.get().name;
processName(name); // which will do some costly operations and make use of the name at the end. 

在上述方法中,我需要等到我的 futureOutput 准备好,即使我稍后才需要它。

我正在寻找类似于以下方法的方法。

CompletableFuture<Output> futureOutput = makeServiceCall(input);
CompletableFuture<String> futureName = futureOutput.get().name; // This is wrong, but can we create a reference in a similar way?
processName(futureName); // which will do some costly operations and make use of the name at the end. 

我可以将 processName 的签名从 String 更改为 CompletableFuture<String> 但不能更改为 CompletableFuture<Output> 因为 Output 没有任何意义对于那个方法。

有什么建议的方法可以让未来的参考成为另一个未来的领域。

您可以将结果提供给新的完成阶段,例如:

CompletableFuture<Output> futureOutput = makeServiceCall(input);
futureOutput.thenAcceptAsync(output -> processName(output.name));

(如果您想阻塞直到操作完成,则使用 thenAccept)。

只需使用CompletableFuture.thenApplyAsync

来自 JavaDoc:

Returns a new CompletionStage that, when this stage completes normally, is executed using this stage's default asynchronous execution facility, with this stage's result as the argument to the supplied function.

在您的示例中(其中 TprocessName 方法的 return 类型):

CompletableFuture<Output> future = makeServiceCall(input);
CompletableFuture<T> result = future.thenApplyAsync(o -> processName(o.name));

现在,当 makeServiceCall CompletableFuture 完成时,会生成另一个 CompletableFuture 来包装对 processName 的异步调用 - 这会创建一个异步管道。

根据您想做什么,您可能会使用 CompletableFuture.thenAcceptAsync 来代替,例如,如果 processName 没有 return 有用的结果:

CompletableFuture<Output> future = makeServiceCall(input);
CompletableFuture<Void> result = future.thenAcceptAsync(o -> processName(o.name));

如果此处理未完成,您可能还需要错误处理,这可以通过 CompletableFuture.exceptionally 完成。这会添加一个回调,如果处理管道以 Exception.

终止,则会调用此回调

通过一个完整的例子,你可以这样做:

makeServiceCall(input)
    .thenApplyAsync(Output::getName)
    .thenAcceptAsync(this::processName)
    .exceptionally(e -> {
        //log the error
        System.out.printf("Oops - %s%n", e);
        //return some useful default value
        return ProcessingResult.SUCCESSFUL;
    });

这个管道(虽然有点做作 - 不需要获得名称 async)是完全异步的。任意点创建任务的Thread无需阻塞;任务要么成功完成,要么调用失败处理程序。