![](/img/trans.png)
[英]CompletionStage, CompletableFuture Void - what to return?
[英]Return CompletableFuture<Void> or CompletableFuture<?>?
我想编写一个返回CompletableFuture
的异步方法。 未来的唯一目的是追踪方法何时完成,而不是结果。 返回CompletableFuture<Void>
或CompletableFuture<?>
会更好CompletableFuture<?>
? 有理由偏爱其中一个,还是可以互换?
CompletableFuture
本身从其许多方法返回CompletableFuture<Void>
。 java.nio
在AsynchronousSocketChannel
有一个Future<Void>
: Future<Void> connect(SocketAddress remote)
。 ExecutorService
和ScheduledExecutorService
这样的java.util.concurrent
类返回Future<?>
:例如,使用Future<?> submit(Runnable task)
。 请注意,我只询问返回类型,而不是参数列表,变量声明或其他上下文。
最好使用CompletableFuture<Void>
。
根据 Sotirios Delimanolis发现的这个答案 , Future<?>
是一个小的API漏洞。 在Java 6中, submit()
方法在内部使用了Future<Object>
,因此其返回类型设置为Future<?>
。 在Java 7中,实现在内部更改为使用Future<Void>
,但是更改API为时已晚,因此返回值仍为Future<?>
。
较新的Java API使用Future<Void>
和CompletableFuture<Void>
。 这些是我们应该遵循的例子。
返回CompletableFuture <Void>或CompletableFuture <?>会更好吗?
有理由偏爱其中一个,还是可以互换?
代码可能会影响三种上下文:
Future<Void>
但不接受Future<?>
。 Future
的结果没有意义,那么通过声明向用户说明这一点是一个好习惯。 所以Future<Void>
是更优选的。
查看CompletableFuture
API,您会发现CompletableFuture<Void>
与副作用一起使用无法获得结果的方法(因为它不存在),例如:
CompletableFuture.runAsync(Runnable runnable);
返回一个CompletableFuture<Object>
会让人感到困惑,因为没有真正的结果,我们只关心完成。 使用Consumers
和Runnables
返回CompletableFuture<Void>
,例如: thenAccept
, thenAcceptAsync
。 Consumer
和Runnable
通常用于副作用。
Void
另一个用例是当你真的不知道结果时。 例如: CompletableFuture.allOf
,传递的列表可能是源自Runnable的CompletableFuture,因此我们无法获得结果。
说完所有这些, CompletableFuture<Void>
只有在你没有其他选择的情况下才有用,如果你可以返回结果然后请去它,如果他们不感兴趣,调用者可能会选择丢弃。 你说你只对完成感兴趣,然后是的, CompletableFuture<Void>
会完成这项工作,但是如果他们知道CompletableFuture<T>
是一个选项并且你只是代表他们决定他们的API用户会讨厌你永远不会需要结果。
合适的类型取决于其语义。 所有列出的选项都承诺信号完成,并可能异步返回异常。
CompletableFuture<Void>
: Void
告诉用户没有预期的结果。 CompletableFuture<?>
?
表示包含值的类型在任何值都可以传递的意义上是未定义的。 CompletableFuture
类从CompletionStage
继承了几个便捷方法。 但是它也允许你的方法的调用者触发未来的完成,这似乎是错误的,因为你的方法负责发出它自己的完成信号。 还有一个cancel(...)
方法在CompletableFuture
的默认实现中毫无意义,因为它不会取消执行。
Future<Void>
: Void
告诉用户没有预期的结果。 Future<?>
?
表示包含值的类型在任何值都可以传递的意义上是未定义的。 Future
缺乏CompletionStage
的便捷方法。 它不允许触发未来的完成,但可以取消执行。
下一个选项是CompletionStage<Void>
:
CompletionStage<Void>
: Void
告诉用户没有预期的结果。 存在绑定处理程序的便捷方法,但cancel(...)
方法不存在。 方法的调用者无法触发CompletionStage
。 <CancellableFuture extends Future<Void> & CompletionStage<Void>>
:来自Future<Void>
和CompletionStage<Void>
。 它告诉没有结果,存在便利方法以及取消选项。 方法的调用者无法触发CompletionStage
。 缺少cancel(...)
方法可能适合您的情况。 因此,如果您不需要取消,我建议使用CompletionStage<Void>
如果您需要取消执行选项,请使用<CancellableFuture extends Future<Void> & CompletionStage<Void>>
。 如果您选择<CancellableFuture extends Future<Void> & CompletionStage<Void>>
您可能想要自己创建一个继承Future<Void>
和CompletionStage<Void>
的接口作为返回类型而不是直接放置long类型的交集在您的方法声明中。
您应该避免使用声明的返回类型CompletableFuture
返回,因为调用者可能会触发将来的完成。 故意这样做会导致令人困惑的代码和令人惊讶的挂起,因为不清楚哪个代码负责触发完成。 使用上述更受限制的类型之一让类型系统防止方法调用者触发意外完成。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.