web-dev-qa-db-ja.com

CompletableFuturesupplyAsync

Java 8.の同時実行機能のいくつかを調査し始めたところです。少し混乱したのは、これらの2つの静的メソッドです。

CompletableFuture<Void> runAsync(Runnable runnable) 
CompletableFuture<U> supplyAsync(Supplier<U> supplier)

インターフェースサプライヤーを使用する理由を誰か知っていますか?値を返すRunnableのアナロジーであるCallableを使用するほうが自然ではありませんか?それは、サプライヤーが処理できない例外をスローしないためですか?

24
Tuan Do

短い答え

いいえ、_CompletableFuture.supplyAsync_でCallableの代わりにSupplierを使用するのは自然なことではありません。議論はほぼ完全にセマンティクスに関するものなので、後でまだ確信が持てない場合でも問題ありません。

長い答え

CallableおよびSupplier機能インターフェース/ SAMタイプは、機能的には実質的に同等です(しゃれを許します)が、その起源と使用目的は異なります。

Callableは、_Java.util.concurrent_パッケージの一部として作成されました。このパッケージは、Java 8のラムダ式に関する大幅な変更の前に提供されたものであり、当初は、従来のハンズオンマルチスレッドモデルから大きく逸脱することなく、並行コードの記述に役立つさまざまなツールに集中していました。

Callableの主な目的は、別のスレッドで実行でき、結果を返すアクションを抽象化することでした。 CallableのJavadocから:

CallableインターフェースはRunnableに似ていますが、どちらもインスタンスが別のスレッドによって実行される可能性があるクラス用に設計されています。

Supplierは、_Java.util.function_パッケージの一部として作成されました。このパッケージは、前述のJava 8.での変更の不可欠な部分として提供されました。このパッケージは、ラムダ式およびメソッド参照のターゲットとなる一般的な関数型を提供します。

そのようなタイプの1つは、結果を返すパラメーターのない関数です(つまり、あるタイプを提供する関数またはSupplier関数)。

それで、なぜSupplierではなくCallableなのか?

CompletableFutureは、前述のJava 8の変更)に触発された_Java.util.concurrent_パッケージへの追加の一部であり、開発者が関数でコードを構築できるようにします。内部で並行性を明示的に処理する代わりに、暗黙的に並列化可能な方法。

そのsupplyAsyncメソッドには、特定のタイプの結果を提供する方法が必要であり、この結果に関心があり、この結果に到達するために実行されるアクションではありません。また、必ずしも例外的な完了を気にする必要はありません(以下のWhat about the ...の段落も参照)。

それでも、Runnableをパラメーターなしの結果なしの機能的インターフェースに使用する場合、Callableをパラメーターなしの単一結果の機能的インターフェースに使用しないでください? =

必ずしも。

パラメータがなく、結果を返さない(したがって、完全に外部コンテキストの副作用によって機能する)関数の抽象化は、_Java.util.function_に含まれていませんでした。これは、そのような機能的なインターフェイスが必要な場合は常に(やや厄介なことに)Runnableが使用されることを意味します。

スローできるチェック済みExceptionについては_Callable.call()

これは、CallableSupplierの意図された意味上の違いの小さな兆候です。

Callableは、別のスレッドで実行できるアクションであり、実行の結果としてその副作用を検査できます。すべてがうまくいくと、特定のタイプの結果が得られますが、一部のアクション(特にマルチスレッドのコンテキスト)を実行すると例外的な状況が発生する可能性があるため、そのような例外的な状況を定義して処理することもできます。

一方、Supplierは、何らかのタイプのオブジェクトを提供するために使用する関数です。例外的な状況は、Supplierの直接の消費者としてのあなたの責任である必要はありません。これはそうです:

  1. ...機能的なインターフェイスは、データを作成または変更するマルチステージプロセスの特定のステージを定義するためによく使用され、Exceptionsの処理は、必要に応じて別のステージにすることができます
  2. ...Exceptionsを明示的に処理すると、関数型インターフェース、ラムダ式、メソッド参照の表現力が大幅に低下します。
15