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


80

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

しかし、Javaコンパイラーではそれができず、try / catchで囲むことをお勧めします。

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

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

通常、私はさせないで完全に元気です run()に例外をスローさ。しかし、私にはその機能が必要な独特の状況があります。

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


他の回答に加えて、タスクの進行状況を追跡するために、FutureTaskクラスを使用できます。
JProgrammer 2012

回答:


26

あなたはその実装クラスを渡したい場合RunnableThreadフレームワークは、その後、あなたはそのフレームワークのルールでプレイしているがそれ以外の場合はそれをやってすることは悪い考えですなぜ、アーネスト・フリードマン・ヒルの答えを参照してください。

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

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

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

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


このような単純な解決策は、「箱の中」を考えないだけで実現しました。もちろん、aRunnableは単純なインターフェースであり、独自のインターフェースを作成できます。スレッドのユースケースには役立ちませんが、この周りにさまざまな「実行可能な」コードのチャンクを渡すのに最適です。
Richard LeMesurier18年

82

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

ときにisDone()trueを返すあなたが呼び出しますFutureTask.get()。あなたがあれば今、Callable投げたException後、FutureTask.get()スローwiillExceptionすぎて、元の例外は、あなたが使用してアクセスすることができるようになりますException.getCause()


23

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

チェックされた例外をrun()メソッドでキャッチしRuntimeException、その場所に変更されていない例外(つまり、)をスローできます。これにより、スタックトレースでスレッドが終了します。おそらくそれがあなたが求めているものです。

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


2
最初の部分は良い議論ではありません。「main()チェックされた例外をスローした場合、何がそれをキャッチしますか?」「run()チェックされていない例外をスローした場合、何がそれをキャッチしますか?」
Christian Hujer 2018年

17

はい、チェックされた例外をからスローする方法がありますrun()メソッド方法はありますが、それはひどいので共有しません。

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

@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より適切です。


しかし、これにより、スロー時にプロセスがクラッシュしますか?
Dinesh 2017

@DineshVGいいえ、JVMのバグのみが真のクラッシュを引き起こす可能性があります。デフォルトの例外ハンドラーは、例外を出力するだけです。その後、プロセスの終了を確認することに慣れている場合は、そのスレッドが実行中の唯一のスレッドであり、終了したためです。
エリクソン2017

これをSOAP呼び出しに使用してみました(Androidインストルメンテーションテストケースで)。SOAP呼び出しから400を取得すると、例外がスローされます。このsoap呼び出しは、テストケースの開始時にスレッドから呼び出されます。このスレッドはこれt.getUncaughtExceptionHandler().uncaughtException(t, ex);を使用して、インストルメンテーションテストケースにスローします。この1行を追加すると、プロセスがクラッシュします。理由はわかりません。
ディネッシュ2017

@DineshVGその環境では、Thread.getDefaultUncaughtExceptionHandler()戻り値はありnullますか?そうでない場合、結果のタイプは何ですか?を呼び出す代わりにuncaughtException()、チェックされた例外をでラップしてRuntimeExceptionそれをスローするとどうなりますか?
エリクソン2017

1
@DineshVG Androidは、これを行うデフォルトのキャッチされない例外ハンドラーを設定している可能性があります。だから私はThread.getDefaultUncaughtExceptionHandler()返品するかどうか尋ねましたnull; そうでない場合、Androidはレポートなどを提供するためにデフォルトを提供しています。ただし、必要に応じて実行するように設定できます。詳細はこちら。
エリクソン2017

6
@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;

}

1

何人かの人々はあなたが規則に従ってプレーしなければならないことをあなたに納得させようとします。聞いてください、しかしあなたが従うかどうか、あなたはあなたの状況に応じてあなた自身を決定するべきです。現実は「ルールに従ってプレイする必要がある」(「ルールに従ってプレイする必要がある」ではない)です。ルールに従わないと、結果が生じる可能性があることに注意してください。

この状況は、の状況だけRunnableでなく、Java 8でも、チェックされた例外を処理する可能性なしに機能インターフェイスが導入されたStreamsやその他の場所のコンテキストで非常に頻繁に当てはまります。例えば、ConsumerSupplierFunctionBiFunctionというように、すべてのチェック例外に対処するための設備なしで宣言されています。

では、状況とオプションは何ですか?以下のテキストでRunnableは、は、例外を宣言しない、または目前のユースケースには制限が多すぎる例外を宣言する機能インターフェイスを表しています。

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

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

@FunctionalInterface
public interface ThrowingRunnable extends Runnable {
    @Override
    default void run() {
        try {
            tryRun();
        } catch (final Throwable t) {
            throwUnchecked(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の将来のバージョンで実際に削除される可能性があります。


0

あなたの要件は意味がありません。発生した例外についてスレッドの呼び出された人に通知したい場合は、コールバックメカニズムを介して通知できます。これは、ハンドラーやブロードキャストなど、考えられるあらゆる方法で行うことができます。


0

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


-1

最も簡単な方法は、RuntimeExceptionクラスの代わりにクラスを拡張する独自の例外オブジェクトを定義することExceptionです。


そして、それが私の親愛なるサーに発生したとき、どのようにこのRuntimeExceptionを手に入れるでしょうか?
ヤマネ2017

それだけでは質問に答えられません。
カールリヒター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.