CompletableFuture
を返す非同期メソッドを書きたい。将来の唯一の目的は、メソッドの結果ではなく、メソッドの完了を追跡することです。 _CompletableFuture<Void>
_または_CompletableFuture<?>
_を返す方が良いでしょうか?どちらかを好む理由はありますか、それとも互換性がありますか?
CompletableFuture
自体は、そのメソッドの多くから_CompletableFuture<Void>
_を返します。Java.nio
_には AsynchronousSocketChannel
:Future<Void> connect(SocketAddress remote)
に_Future<Void>
_があります。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 <?>を返す方が良いでしょうか?
どちらかを好む理由はありますか、それとも互換性がありますか?
コードが影響する可能性がある3つのコンテキストがあります。
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
のもう1つの使用例は、結果が本当にわからない場合です。例:CompletableFuture.allOf
、渡されたリストはRunnableから生成されたCompletableFutureである可能性があるため、結果を取得できません。
そうは言っても、CompletableFuture<Void>
は、別のオプションがない場合にのみ有効です。結果を返すことができる場合は、結果に戻ってください。呼び出し側は、興味がない場合は破棄することを選択できます。あなたは完了にのみ興味があると言ったので、はい、CompletableFuture<Void>
は仕事をしますが、CompletableFuture<T>
がオプションであり、あなたが彼らに代わって決めただけなら、APIユーザーはあなたを嫌います彼らが結果を必要としないこと。
適切なタイプは、そのセマンティックに依存します。リストされたオプションはすべて、完了を通知することを約束し、非同期的に例外を返す場合があります。
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
で戻ることは避けてください。意図的にこれを行うと、どのコードが完了をトリガーするのかが明確ではないため、コードが混乱し、驚くべきハングが発生します。上記のより制限された型のいずれかを使用して、型システムがメソッドの呼び出し元による意図しない完了トリガーを防止できるようにします。