返回CompletableFuture<Void>还是CompletableFuture<?>?(涉及IT技术)

69

我希望编写一个异步方法,返回一个CompletableFuture。该future的唯一目的是跟踪方法何时完成,而不是其结果。返回CompletableFuture<Void>还是CompletableFuture<?>更好?有没有理由偏好其中之一,或者它们可以互换?

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

4个回答

32

最好使用CompletableFuture<Void>

根据Sotirios Delimanolis发现的这个答案,Future<?>是一个小型API缺陷。在Java 6中,submit()方法内部使用了Future<Object>,因此它的返回类型被设置为Future<?>。在Java 7中,实现更改为在内部使用Future<Void>,但是改变API已经太晚了,因此返回值仍然是Future<?>

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


18
返回结果:

返回 CompletableFuture<Void> 还是 CompletableFuture<?> 更好?

有没有理由更喜欢其中一个,或者它们可以互换使用?

代码可能影响三种情况:

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

因此,Future<Void> 更可取。


16

查看 CompletableFuture API,您会发现 CompletableFuture<Void> 与副作用方法一起使用,其中结果无法获取(因为它不存在),例如:

CompletableFuture.runAsync(Runnable runnable);
返回一个 `CompletableFuture` 在这里会很清晰明了,因为我们只关心它是否完成。那些接受 ConsumersRunnables 的方法会返回 CompletableFuture<Void>,例如: thenAccept, thenAcceptAsync。通常情况下,ConsumerRunnable 用于产生副作用。
另一个使用 Void 的案例是当你真的不知道结果时。例如:CompletableFuture.allOf,传递的列表可能是由 Runnable 生成的 CompletableFuture,所以我们无法获取结果。
话虽如此,仅当你没有其他选择时,CompletableFuture<Void> 才是好的选择。如果可以返回结果,则请这样做,调用方可能会选择丢弃结果。如果你说你只关心完成,那么是的,CompletableFuture<Void> 可以胜任,但如果 API 用户知道 CompletableFuture<T> 是一个选项而你已经替他们决定了他们永远不需要结果,他们会讨厌你的。

7
合适的类型取决于其语义。所有列出的选项都承诺信号完成并可能异步返回异常。
- CompletableFuture<Void>: Void表示不需要期望结果。 - CompletableFuture<?>: ?表示包含值的类型未定义,任何值都可以传递。
CompletableFuture类从CompletionStage继承了几个方便的方法。但是,它也允许您方法的调用者触发future的完成,这似乎是错误的,因为您的方法负责自己发出完成信号。还有一个cancel(...)方法,在CompletableFuture的默认实现中相当无意义,因为它不会取消执行。
- Future<Void>: Void表示不需要期望结果。 - Future<?>: ?表示包含值的类型未定义,任何值都可以传递。
Future缺少来自CompletionStage的便利方法。它不允许触发future的完成,但执行可以被取消。
下一个选项是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>,以作为返回类型而不是直接将长类型交叉放在方法声明中。

您应该避免使用声明了返回类型 CompletableFuture 的返回,因为调用者有可能触发 future 的完成。这样做会导致代码混乱和意外的挂起,因为不清楚哪个代码负责触发完成。使用提到的更受限制的类型之一,让类型系统防止方法调用者意外触发完成。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接