web-dev-qa-db-ja.com

Runnableのrun()がチェック済みの例外をスローできないのはなぜですか?

[〜#〜] jcip [〜#〜] のセクション6.3.2によると:

Runnableはかなり限定的な抽象化です。 runは値を返すことも、チェックされた例外をスローすることもできません。

run()は、戻り値の型が無効であるため値を返すことができませんが、チェックされた例外をスローできないのはなぜですか?

17
Inquisitive

最初のバージョンからチェック例外をスローするように宣言されておらず、変更するには危険すぎるため、チェック例外をスローすることはできません。

元々、RunnableはラップされたThreadでのみ使用され、開発者はSystem.errにログを記録するのではなく、チェックされたすべての例外をキャッチして処理したいと考えていました。

Callableは、個々のタスクをExecutorに追加できる場合に追加されました。ここで、結果をFutureおよびスローされた例外でキャプチャできます。

Callableで値を返し、オプションでチェック済み例外を宣言できるようになりました。

[〜#〜] btw [〜#〜]:呼び出し可能オブジェクトからの戻りを望まない、またはチェックされた例外をスローしないと言うことができる1つの方法は、次のようなものを使用することです。

Callable<Void> callable = new Callable<Void>() {
    public Void call() {
        // do something
        return null;
    }
};
23
Peter Lawrey

これは質問に対する答えではありません。むしろ、これは Lukas Ederの回答 のフォローアップであり、静的に許可されていない場所にチェック済みの例外を密輸する別の方法を示しています。これは、引数のないコンストラクターが newInstance で呼び出された場合、それがスローするチェックされた例外はすべて上向きにエスケープされるという事実に依存しています。

public class Thrower {

    private static final ThreadLocal<Exception> toThrow = new ThreadLocal<Exception>();

    public static void throwUnsafely(Exception e) {
        try {
            toThrow.set(e);
            Thrower.class.newInstance();
        } catch (InstantiationException f) {
            throw new RuntimeException("unexpected exception while throwing expected exception", f);
        } catch (IllegalAccessException f) {
            throw new RuntimeException("unexpected exception while throwing expected exception", f);
        } finally {
            toThrow.remove();
        }
    }

    private Thrower() throws Exception {
        throw toThrow.get();
    }

}

これはクラスです-本当に古代の黒い帽子Javaブードゥー。決してこれをしないでください。人々を感動させるパーティーを除いて。

5
Tom Anderson

run() 宣言されていないため、チェックされた例外をスローできません。チェックされた例外を宣言せずにスローすることはできません。

また、その例外をスローしない別のメソッドをオーバーライドまたは実装するメソッドで、チェックされた例外を宣言することはできません。したがって、Runnableの実装では、run()の実装にthrows句を単純に追加することはできません。

4
Tom Anderson

チェックされた例外をいつでも安全にスローできません。

import Java.lang.reflect.Field;
import Sun.misc.Unsafe;

public class UnsafeSample {
    public void methodWithNoDeclaredExceptions( ) {
        Unsafe unsafe = getUnsafe();
        unsafe.throwException( new Exception( "this should be checked" ) );
    }

    private Unsafe getUnsafe() {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main( String[] args ) {
        new UnsafeSample().methodWithNoDeclaredExceptions();
    }
}

こちらの記事全文をご覧ください:

http://Java.dzone.com/articles/throwing-undeclared-checked

別の選択肢:

public class Test {
    public static void main(String[] args) {
        doThrow(new SQLException());
    }

    public static void doThrow(Exception e) {
        Test.<RuntimeException> doThrow0(e);
    }

    @SuppressWarnings("unchecked")
    public static <E extends Exception> void doThrow0(Exception e) throws E {
        throw (E) e;
    }
}

これはここに示されています:

http://Java.dzone.com/articles/throw-checked-exceptions

そうは言っても、やらないでください! ;-)

2
Lukas Eder

Runnableでシグネチャvoidrun()を保持する背後にある動機は、他のメソッドのように呼び出されることを意図しておらず、CPUスレッドスケジューラによって呼び出されるように設計されていることだと思います。もしそうなら、誰がその戻り値を受け取り、誰がこれによってスローされたチェック済み例外を処理するのか。 ncaughtExceptionHandler はJava 5.0で、スレッドによってスローされたキャッチされなかった例外を処理します。ExecutorFrameworkは、戻り値またはスローされた例外(ExecutionExceptionのラッパー)をいくつかの状態として保存します。スレッド間で共有されるオブジェクト(外部クラスインスタンスなど)は、Futureの呼び出し元(他のスレッドで実行されている)にそれらを提供します。 get ()。

2

Runnable Interface を見ると、void run()メソッドがチェックされた例外をスローするものとして宣言されておらず、ThreadクラスがRunnableInterfaceを実装していることがわかります。

[〜#〜] jls [〜#〜] は、メソッドm1がインターフェイス/スーパークラスで宣言されていない場合、例外をスローできないことを示しています。

2
amicngh