JavaのRunnable
とインターフェイスの違いを理解しました。Callable
Java 1.5 から追加機能がRunnable
インターフェースに追加されCallable
、下位互換性を維持するために呼び出されました。
私の質問はCallable
、インターフェースができたので、常にそれを使用しますか? Callable
を使用しない場合と使用する場合のユースケースは何Runnable
ですか?
(これは、それらの違いについての良い記事です)
JavaのRunnable
とインターフェイスの違いを理解しました。Callable
Java 1.5 から追加機能がRunnable
インターフェースに追加されCallable
、下位互換性を維持するために呼び出されました。
私の質問はCallable
、インターフェースができたので、常にそれを使用しますか? Callable
を使用しない場合と使用する場合のユースケースは何Runnable
ですか?
(これは、それらの違いについての良い記事です)
どちらにも用途があり、どちらも java.util.concurrent の Executor フレームワークでサポートされています。Runnable は以前から存在していますが、現在も使用されており、推奨されていません。
Callable は例外をスローして値を返すことができるため、結果を伴うタスク (ネットワークからのリソースのフェッチ、値の高価な計算の実行など) をより適切に抽象化できます [ Goetz によるJava Concurrency in Practiceから、ブロッホら。al.、Java 並行性に関する標準的な作業]。
したがって、API を設計している場合は、可能であれば Callables を使用することをお勧めします。タスクが値を返さず、例外をスローしないことが確実な場合は、ランナブルも有効な選択です。特に Runnable は Callable に簡単にラップでき、その逆も同様であるため、白黒はありません。
余談ですが、 Callable 実装はthrows Exception
;を宣言する必要がないことに注意してください。Callable 自体が宣言しているのは、実装者がチェック済みの例外をスローできるようにするためだけです。ただし、Callable インターフェースのみに依存する Callable の呼び出し元は、例外処理コードを作成する必要があります。
Callable は値を返す必要がないことにも注意してください。Callable を返すように宣言するだけですVoid
(大文字の ' V
' を使用)。
Callable
:を使用しないユース ケースであり、のみScheduledExecutorService.scheduleAtFixedRate
をscheduleWithFixedDelay
受け入れますRunnable
。
私は s を好みますが、を にCallable
する必要があるまれなケースでは、このようなメソッドを に追加することで両方を簡単に実装できます。Callable
Runnable
run()
Callable
public void run(){
try{
call();
} catch (Exception e){
e.printStackTrace(); // or however you log errors
}
}
Java 8 では、同じことを行うインターフェースを作成することもできます。
public interface CallableRunnable<T> extends Callable<T>, Runnable {
default void run(){
try {
call();
} catch (Exception e) {
e.printStackTrace(); // or however you log errors
}
}
}
implements Callable<T>
次に、それを何かに変更するだけです。そうすればimplements CallableRunnable<T>
、ジョブは、いずれかを必要とする任意のメソッドからいつでも呼び出すことができます。もちろん、特定のエラー処理が必要な場合でも、run() メソッドをオーバーライドして、call()
メソッドによってスローされた例外を処理できます。そのためのメソッドを実装することもできます。
public interface CallableRunnable<T> extends Callable<T>, Runnable {
default void run(){
try {
call();
} catch (Exception e) {
handleCallExceptions(e);
}
}
default void handleCallExceptions(Exception e){
e.printStackTrace();
}
}
次に、特別な例外処理は独自のhandleExceptions(Exception)
メソッドを実装するだけで済みます...しかし、必要がなければ実装する必要はありません。ロギング フレームワークなどを使用する実装を使用できるため、これを好みます。