返回void与返回CompletionStage <Void>有什么区别?

时间:2019-12-23 21:08:36

标签: java asynchronous completable-future

更具体地说,这两段代码有什么区别,一个返回void,另一个返回CompletionStage<Void>

  • 使用voidCompletionStage<Void>中的一个相对于另一个有什么优势?
  • 在代码示例2中,我没有使用x中的变量thenCompose。有没有更好的书写方式?
  • 如果我在函数boolean中返回doValidation并检查true函数中的performTask是否是更好的做法?

代码示例1:

public CompletionStage<Response> performTask(Request request) throws MyException {
    doValidation(request);
    return service.performTask(request).thenCompose(serviceResponse -> CompletableFuture.completedFuture(buildMyResponse(serviceResponse)));
}

private void doValidation(Request request) throws MyException {
    CompletableFuture.runAsync(() -> {
        // Validate
        if (*someCondition*) {
            throw new MyException(.....);
        }
    });
}

代码示例2:

public CompletionStage<Response> performTask(Request request) throws MyException {
    return doValidation(request).thenCompose(x -> {
        return service.performTask(request).thenCompose(serviceResponse -> CompletableFuture.completedFuture(buildMyResponse(serviceResponse)));
    });
}

private CompletionStage<Void> doValidation(Request request) throws MyException {
    return CompletableFuture.runAsync(() -> {
        // Validate
        if (*someCondition*) {
            throw new MyException(.....);
        }
    });
}

2 个答案:

答案 0 :(得分:2)

我正在解决您的第一个问题

What advantages of using one of void or CompletionStage<Void> over the other?

要了解差异,您应该尝试记录流程。它将帮助您确定两者的工作方式有何不同。

这是与您遵循的方法类似的示例。我提出了自己的示例,因为我不知道您的代码。

public class Test {

    public static void main(String[] args) {
        tryWithVoid();
        //      tryWithCompletionStageVoid();
    }

    public static void tryWithVoid() {
        System.out.println("Started");
        validate(null);
        System.out.println("Exit");
    }

    public static void tryWithCompletionStageVoid() {
        System.out.println("Started");
        validateCS(null).thenRun(() -> System.out.println("Validation complete"));
        System.out.println("Exit");
    }

    public static CompletionStage<Void> validateCS(String val) {
        return CompletableFuture.runAsync(() -> {
            if (val == null) {
                System.out.println("Validation failed! value is null");
            }
        });
    }

    public static void validate(String val) {
        CompletableFuture.runAsync(() -> {
            if (val == null) {
                System.out.println("Validation failed! value is null");
            }
        });
    }
}

如果运行tryWithVoid(),您将看到输出为:

Started
Exit
Validation failed! value is null

运行tryWithCompletionStageVoid()时,它将是:

Started
Validation failed! value is null
Validation complete
Exit

在第一种方法tryWithVoid()中,它不等待操作完成。因此,调用后的代码可能无法获得操作结果。

但是,在第二种方法tryWithCompletionStageVoid()中,它在运行下一阶段之前等待该阶段完成。

如果您在各个阶段之间没有依赖性,则可以使用void

答案 1 :(得分:2)

区别在于,返回void后,您将无法执行链接到CompletableFuture的任何操作。

当您返回CompletableFuture<Void>时,您可以将其他内容链接到它。例如,调用thenRun()thenRunAsync()或仅调用join()来等待它完成(如果需要)。

因此,这取决于调用方是否关心CompletableFuture的状态,并希望应用附加的逻辑。

在您的情况下,在示例1中,doValidation()在单独的线程上运行,而发生的任何事情实际上都是无关紧要的。 service.performTask()的发生与它无关,甚至可以在doValidation()之前开始和/或结束。

在示例2中,doValidation()必须成功完成performTask()才能实际完成。因此,似乎该版本实际上是正确的版本。请记住,正在运行CompletionStage<Response> performTask() main 线程将完成并在设置管道后立即返回,实际的performValidation()可能仍在运行(甚至可能尚未启动)。 。

通过以下方式可以简化通话:

service.performTask(request).thenApply(this::buildMyResponse);

您不必再次将其包装在CompletableFuture中,而只需用thenCompose()重新包装。