返回 void 与返回 CompletionStage<Void> 之间有什么区别吗?
Is there any difference between returning a void vs returning a CompletionStage<Void>?
更具体地说,有什么区别,在这两段代码中,一个 returning void
和另一个 returning CompletionStage<Void>
?
- 使用
void
或 CompletionStage<Void>
中的一个比另一个有什么优势?
- 在代码示例 2 中,我没有在
thenCompose
中使用变量 x
。有没有更好的写法?
- 如果我在函数
doValidation
中 return 一个 boolean
并检查 performTask
函数中是否有 true
是否更好?
代码示例 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(.....);
}
});
}
我正在回答你的第一个问题
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
不同之处在于,使用 returning a void
你不能在 CompletableFuture
完成后做任何链接到 CompletableFuture
的事情。
当您 return CompletableFuture<Void>
时,您可以将更多内容链接到它。例如调用 thenRun()
、thenRunAsync()
或只是 join()
以等待它在需要时完成。
所以这取决于调用者是否关心 CompletableFuture
的状态并希望应用附加到它的进一步逻辑。
在你的例子中,在示例 1 中,doValidation()
是 运行 在一个单独的线程上,无论它发生什么都无关紧要。 service.performTask()
将独立于它发生,甚至可以在 doValidation()
之前开始 and/or 完成。
在示例 2 中,doValidation()
必须在 performTask()
实际发生之前成功完成。所以看起来这个版本实际上是正确的。请记住 main 线程 运行 CompletionStage<Response> performTask()
将在设置管道后立即完成并且 return ,实际的 performValidation() 仍然可以运行(或者甚至可能还没有开始)。
顺便说一句,你可以简化调用如下:
service.performTask(request).thenApply(this::buildMyResponse);
您不必再次用 CompletableFuture
包装它,只需用 thenCompose()
再次打开它即可。
更具体地说,有什么区别,在这两段代码中,一个 returning void
和另一个 returning CompletionStage<Void>
?
- 使用
void
或CompletionStage<Void>
中的一个比另一个有什么优势? - 在代码示例 2 中,我没有在
thenCompose
中使用变量x
。有没有更好的写法? - 如果我在函数
doValidation
中 return 一个boolean
并检查performTask
函数中是否有true
是否更好?
代码示例 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(.....);
}
});
}
我正在回答你的第一个问题
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
不同之处在于,使用 returning a void
你不能在 CompletableFuture
完成后做任何链接到 CompletableFuture
的事情。
当您 return CompletableFuture<Void>
时,您可以将更多内容链接到它。例如调用 thenRun()
、thenRunAsync()
或只是 join()
以等待它在需要时完成。
所以这取决于调用者是否关心 CompletableFuture
的状态并希望应用附加到它的进一步逻辑。
在你的例子中,在示例 1 中,doValidation()
是 运行 在一个单独的线程上,无论它发生什么都无关紧要。 service.performTask()
将独立于它发生,甚至可以在 doValidation()
之前开始 and/or 完成。
在示例 2 中,doValidation()
必须在 performTask()
实际发生之前成功完成。所以看起来这个版本实际上是正确的。请记住 main 线程 运行 CompletionStage<Response> performTask()
将在设置管道后立即完成并且 return ,实际的 performValidation() 仍然可以运行(或者甚至可能还没有开始)。
顺便说一句,你可以简化调用如下:
service.performTask(request).thenApply(this::buildMyResponse);
您不必再次用 CompletableFuture
包装它,只需用 thenCompose()
再次打开它即可。