web-dev-qa-db-ja.com

CompletableFuture <Void>またはCompletableFuture <?>を返しますか?

CompletableFuture を返す非同期メソッドを書きたい。将来の唯一の目的は、メソッドの結果ではなく、メソッドの完了を追跡することです。 _CompletableFuture<Void>_または_CompletableFuture<?>_を返す方が良いでしょうか?どちらかを好む理由はありますか、それとも互換性がありますか?

  • CompletableFuture 自体は、そのメソッドの多くから_CompletableFuture<Void>_を返します。
  • _Java.nio_には AsynchronousSocketChannelFuture<Void> connect(SocketAddress remote)に_Future<Void>_があります。
  • 一方、 ExecutorServiceScheduledExecutorService のような_Java.util.concurrent_クラスは_Future<?>_を返します。たとえば、 Future<?> submit(Runnable task)

パラメーターリスト、変数宣言、その他のコンテキストではなく、戻り値の型についてのみ質問していることに注意してください。

44
John Kugelman

_CompletableFuture<Void>_を使用するのが最善です。

この回答によれば 発見 Sotirios Delimanolis 、_Future<?>_はマイナーなAPIの欠陥です。 Java 6では、submit()メソッドは内部で_Future<Object>_を使用したため、その戻り値の型は_Future<?>_に設定されていました。 Java 7では、実装が_Future<Void>_を内部で使用するように変更されましたが、APIを変更するには遅すぎたため、戻り値は_Future<?>_のままでした。

新しいJava AP​​Iは_Future<Void>_および_CompletableFuture<Void>_を使用します。これらは従うべき例です。

19
John Kugelman

CompletableFuture <Void>またはCompletableFuture <?>を返す方が良いでしょうか?

どちらかを好む理由はありますか、それとも互換性がありますか?

コードが影響する可能性がある3つのコンテキストがあります。

  • ランタイム-ジェネリックには影響がありません。
  • コンパイル-いくつかのメソッドがFuture<Void>を受け入れるが、Future<?>を受け入れない場合は想像できません。
  • 開発-Futureの結果に意味がない場合、宣言を通じてユーザーにそのことを伝えるのは良い習慣です。

したがって、Future<Void>がより望ましいです。

17
user3707125

CompletableFuture AP​​Iを見ると、CompletableFuture<Void>が、結果が得られない(存在しないため)副作用のあるメソッドで使用されていることがわかります。例:

CompletableFuture.runAsync(Runnable runnable);

ここにCompletableFuture<Object>を返すことは混乱を招くでしょう。なぜなら、実際には結果がなく、完了だけが重要だからです。 ConsumersおよびRunnablesをとるメソッドは、CompletableFuture<Void>を返します。例:thenAcceptthenAcceptAsyncConsumerおよびRunnableは、一般的な副作用に使用されます。

Voidのもう1つの使用例は、結果が本当にわからない場合です。例:CompletableFuture.allOf、渡されたリストはRunnableから生成されたCompletableFutureである可能性があるため、結果を取得できません。

そうは言っても、CompletableFuture<Void>は、別のオプションがない場合にのみ有効です。結果を返すことができる場合は、結果に戻ってください。呼び出し側は、興味がない場合は破棄することを選択できます。あなたは完了にのみ興味があると言ったので、はい、CompletableFuture<Void>は仕事をしますが、CompletableFuture<T>がオプションであり、あなたが彼らに代わって決めただけなら、APIユーザーはあなたを嫌います彼らが結果を必要としないこと。

9
Sleiman Jneidi

適切なタイプは、そのセマンティックに依存します。リストされたオプションはすべて、完了を通知することを約束し、非同期的に例外を返す場合があります。

  • _CompletableFuture<Void>_:Voidは、予期される結果がないことをユーザーに伝えます。
  • _CompletableFuture<?>_ _?_は、値を配信できるという意味で、contains値の型が未定義であることを意味します。

CompletableFutureクラスは、CompletionStageからいくつかの便利なメソッドを継承します。しかし、メソッドの呼び出し元が将来の完了をトリガーすることもできます。これは、メソッド自体が完了を知らせる責任があるため、間違っているように見えます。 cancel(...)メソッドもあります。これは、実行をキャンセルしないため、CompletableFutureのデフォルト実装ではほとんど意味がありません。

  • _Future<Void>_:Voidは、予期される結果がないことをユーザーに伝えます。
  • _Future<?>_ _?_は、値を配信できるという意味で、contains値の型が未定義であることを意味します。

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>>_を選択した場合は、メソッド宣言にlong型の共通部分を直接配置する代わりに、_Future<Void>_および_CompletionStage<Void>_を継承するインターフェイスを自分で作成して戻り型として使用することをお勧めします。

呼び出し元が将来の完了をトリガーする可能性があるため、宣言された戻り型CompletableFutureで戻ることは避けてください。意図的にこれを行うと、どのコードが完了をトリガーするのかが明確ではないため、コードが混乱し、驚くべきハングが発生します。上記のより制限された型のいずれかを使用して、型システムがメソッドの呼び出し元による意図しない完了トリガーを防止できるようにします。

5
Augustus Kling