62

我想编写一个返回CompletableFuture. 未来的唯一目的是跟踪方法何时完成,而不是其结果。是返回更好CompletableFuture<Void>还是CompletableFuture<?>?是否有理由偏爱其中一个,或者它们可以互换?

请注意,我只询问返回类型,而不是参数列表、变量声明或其他上下文。

4

4 回答 4

29

最好使用CompletableFuture<Void>.

根据Sotirios Delimanolis找到的这个答案,这Future<?>是一个小的 API 缺陷。在 Java 6 中,该submit()方法在Future<Object>内部使用 a,因此其返回类型设置为Future<?>. 在 Java 7 中,实现改为在Future<Void>内部使用,但更改 API 为时已晚,因此返回值保持为Future<?>.

较新的 Java API 使用Future<Void>CompletableFuture<Void>. 这些是我们应该遵循的例子。

于 2016-08-17T17:16:05.880 回答
18

返回 CompletableFuture<Void> 或 CompletableFuture<?> 会更好吗

是否有理由偏爱其中一个,或者它们可以互换?

代码可能会影响三种上下文:

  • 运行时 - 泛型对此没有任何影响。
  • 编译 - 我无法想象某些方法会接受Future<Void>但不会接受的情况Future<?>
  • 开发 - 如果Future的结果没有意义,那么通过声明向用户说明这一点是一个好习惯。

所以Future<Void>更可取。

于 2015-12-11T22:46:00.567 回答
15

查看CompletableFutureAPI,您会发现它CompletableFuture<Void>与无法获得结果的副作用类型的方法一起使用(因为它不存在),例如:

CompletableFuture.runAsync(Runnable runnable);

在这里返回 a CompletableFuture<Object>会令人困惑,因为真的没有结果,我们只关心完成。接受ConsumersRunnables返回的方法CompletableFuture<Void>,例如 : thenAccept, thenAcceptAsync. Consumer并且Runnable通常用于副作用。

另一个用例Void是当你真的不知道结果时。例如:CompletableFuture.allOf,传递的列表可能是来自 Runnable 的 CompletableFuture,所以我们无法得到结果。

说了这么多,CompletableFuture<Void>只有在你没有其他选择的情况下才好,如果你可以返回结果,那就去吧,如果调用者不感兴趣,他们可能会选择丢弃。您说您只对完成感兴趣,那么是的,CompletableFuture<Void>会完成这项工作,但是如果您的 API 用户知道这CompletableFuture<T>是一个选项并且您只是代表他们决定他们永远不需要结果,他们会讨厌您。

于 2015-12-11T22:55:08.370 回答
7

合适的类型取决于它的语义。所有列出的选项都承诺发出完成信号,并可能异步返回异常。

  • CompletableFuture<Void>:Void告诉用户没有预期的结果。
  • CompletableFuture<?>?意味着包含值的类型在可以传递任何值的意义上是未定义的。

该类CompletableFutureCompletionStage. 但它也允许您的方法的调用者触发未来的完成,这似乎是错误的,因为您的方法负责自己发出信号完成。还有一种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因为调用者可能会触发未来的完成。这样做会故意导致代码混乱和令人惊讶的挂起,因为现在还不清楚哪个代码负责触发完成。使用上述更受限制的类型之一,让类型系统防止您的方法的调用者无意中触发完成。

于 2016-11-26T00:50:05.550 回答