86

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

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

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

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

通常、 run()に例外をスローさせなくても問題ありません。しかし、私にはその機能が必要な独特の状況があります。

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

4

9 に答える 9

90

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

isDone()trueを返す場合は、を呼び出しますFutureTask.get()。これで、Callableをスローした場合はException、もFutureTask.get()スローしException、元の例外をスローして、を使用してアクセスできるようになりますException.getCause()

于 2012-07-20T17:32:37.103 に答える
36

Runnableフレームワークに実装するクラスを渡したい場合はThread、そのフレームワークのルールに従ってプレイする必要があります。アーネストフリードマンヒルの回答を参照してください。そうでない場合にそれを行うのは悪い考えです。

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

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

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

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

于 2012-07-20T17:36:42.073 に答える
27

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

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

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

于 2012-07-20T17:28:41.497 に答える
19

はい、メソッドからチェックされた例外をスローする方法があります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より適切です。

于 2012-07-20T17:34:44.633 に答える
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;

}
于 2018-11-20T17:07:13.940 に答える
2

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

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

では、状況とオプションは何ですか?以下のテキストで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の将来のバージョンで実際に削除される可能性があります。

于 2018-11-24T08:52:45.117 に答える
0

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

于 2012-07-20T17:29:22.643 に答える
0

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

于 2012-07-20T17:32:22.283 に答える
-1

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

于 2016-03-15T03:02:25.970 に答える