4

我正在调用返回 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我可以将from的签名更改为StringtoCompletableFuture<String>但不更改CompletableFuture<Output>为 asOutput对该方法没有任何意义。

有哪些建议的方法来获得未来参考,这是另一个未来的领域。

4

2 回答 2

6

只需使用CompletableFuture.thenApplyAsync

来自 JavaDoc:

返回一个新的 CompletionStage,当此阶段正常完成时,将使用此阶段的默认异步执行工具执行该阶段,并将此阶段的结果作为所提供函数的参数。

在您的示例中(方法T的返回类型在哪里processName):

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

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

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

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创建任务的;任务要么成功完成,要么调用失败处理程序。

于 2015-09-02T10:34:50.160 回答
0

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

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

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

于 2015-09-02T10:34:29.130 回答