web-dev-qa-db-ja.com

Runnableのrun()に例外をスローさせる方法はありますか?

runnable )を実装するクラスで run() で呼び出しているメソッドは、例外をスローするように設計されています。

しかし、Javaコンパイラーはそれを許可せず、try/catchで囲むことを提案します。

問題は、それをtry/catchで囲むことでその特定のrun() 役に立たないことです。 Idoその例外をスローしたい。

run() 自体にthrowsを指定すると、コンパイラはException is not compatible with throws clause in Runnable.run()と文句を言います。

通常、私は run() に例外をスローさせなくても大丈夫です。しかし、私はその機能を持たなければならないユニークな状況にあります。

この制限を回避するにはどうすればよいですか?

65
Regex Rookie

Runnableを実装するクラスをThreadフレームワークに渡したい場合は、そのフレームワークのルールに従って操作する必要があります。それ以外の場合は悪いアイデアである理由を説明するErnest Friedman-Hillの回答を参照してください。

ただし、コード内でrunメソッドを直接呼び出して、呼び出し元のコードが例外を処理できるようにしたいという思いがあります。

この問題への答えは簡単です。スレッドライブラリのRunnableインターフェイスを使用しないでください。代わりに、チェックされた例外をスローできるように変更されたシグネチャを持つ独自のインターフェイスを作成してください。

public interface MyRunnable
{
    void myRun ( ) throws MyException;
}

スレッドフレームワークでの使用に適した実際のRunnable(チェック済み例外を処理することにより)にこのインターフェイスを変換するアダプターを作成することもできます。

17

代わりにCallableを使用して、ExecutorServiceに送信し、FutureTask.isDone()によって返されるExecutorService.submit()で結果を待つことができます。

isDone()がtrueを返すとき、FutureTask.get()を呼び出します。 CallableExceptionをスローした場合、FutureTask.get()Exceptionもスローし、元の例外はException.getCause()

71

run()がチェック例外をスローした場合、何がキャッチされますか? run()呼び出しをハンドラーで囲む方法はありません。それを呼び出すコードを記述しないためです。

run()メソッドでチェック済みの例外をキャッチし、代わりに未変更の例外(つまり、RuntimeException)をスローできます。これにより、スタックトレースでスレッドが終了します。おそらくそれがあなたの望みです。

代わりにrun()メソッドでエラーをどこかに報告したい場合は、run()メソッドのcatchブロックが呼び出すコールバックメソッドを提供するだけです。そのメソッドは例外オブジェクトをどこかに保存し、関心のあるスレッドがその場所でオブジェクトを見つけることができます。

20

はい、run()メソッドからchecked例外をスローする方法がありますが、とてもひどいので共有しません。

代わりにできることは次のとおりです。ランタイム例外が実行するのと同じメカニズムを使用します。

_@Override
public void run() {
  try {
    /* Do your thing. */
    ...
  } catch (Exception ex) {
    Thread t = Thread.currentThread();
    t.getUncaughtExceptionHandler().uncaughtException(t, ex);
  }
}
_

他の人が指摘したように、run()メソッドが実際にThreadのターゲットである場合、例外はスローされないため、例外をスローしても意味がありません。例外をスローすると、例外をスローしないのと同じ効果があります(なし)。

Threadターゲットでない場合は、Runnableを使用しないでください。たとえば、おそらく Callable の方が適しています。

16
erickson
@FunctionalInterface
public interface CheckedRunnable<E extends Exception> extends Runnable {

    @Override
    default void run() throws RuntimeException {
        try {
            runThrows();
        }
        catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    void runThrows() throws E;

}
3
Sina Madani

一部の人々は、ルールに従ってプレーしなければならないことをあなたに納得させようとします。聞いてください。しかし、従うかどうかは、状況に応じて自分で決める必要があります。現実は、「ルールに従ってプレイする必要があります」ではなく「ルールに従ってプレイする必要があります」です。ルールを守らないと、結果が生じる可能性があることに注意してください。

この状況はRunnableの状況に適用されるだけでなく、Java 8を使用して、ストリームや、機能インターフェースが導入されていない他の場所のコンテキストでも非常に頻繁にたとえば、ConsumerSupplierFunctionBiFunctionなどはすべて、チェック例外を処理する機能なしで宣言されています。

それでは、状況とオプションは何ですか?以下のテキストでは、Runnableは、例外を宣言しない、または手元のユースケースに対して限定されすぎる例外を宣言するすべての機能インターフェイスを表しています。

  1. 自分でRunnableを宣言したので、Runnableを別のものに置き換えることができます。
    1. Runnableを_Callable<Void>_に置き換えることを検討してください。基本的に同じことですが、例外をスローできます。最後に_return null_する必要がありますが、これはやや面倒です。
    2. Runnableを、必要な例外を正確にスローできる独自のカスタム_@FunctionalInterface_に置き換えることを検討してください。
  2. APIを使用しましたが、代替手段が利用可能です。たとえば、一部のJava APIはオーバーロードされるため、Runnableの代わりに_Callable<Void>_を使用できます。
  3. APIを使用しましたが、代替手段はありません。その場合、あなたはまだ選択肢がありません。
    1. RuntimeExceptionで例外をラップできます。
    2. チェックされていないキャストを使用して、例外をRuntimeExceptionにハックできます。

以下を試すことができます。ちょっとしたハックですが、時にはハックが必要な場合もあります。なぜなら、例外をチェックするかどうかは、そのタイプによって定義されますが、実際には状況によって実際に定義される必要があるためです。

_@FunctionalInterface
public interface ThrowingRunnable extends Runnable {
    @Override
    default void run() {
        try {
            tryRun();
        } catch (final Throwable t) {
            throwUnchecekd(t);
        }
    }

    private static <E extends RuntimeException> void throwUnchecked(Throwable t) {
        throw (E) t;
    }

    void tryRun() throws Throwable;
}
_

new RuntimeException(t)よりもスタックトレースが短いので、こちらが好きです。

次のことができます。

_executorService.submit((ThrowingRunnable) () -> {throw new Exception()});
_

免責事項:この方法で未チェックのキャストを実行する機能は、ジェネリック型情報がコンパイル時だけでなく実行時にも処理されるときに、将来のバージョンのJavaで実際に削除される可能性があります。

1
Christian Hujer

リスナーパターン がこのシナリオに役立つと思います。 run()メソッドで例外が発生した場合、try-catchブロックを使用し、catchで例外イベントの通知を送信します。そして、通知イベントを処理します。これはよりクリーンなアプローチだと思います。 このSOリンク は、その方向への有用なポインタを提供します。

0
Sujay