为什么runnable run()不能抛出已检查的异常?

时间:2012-07-10 09:08:15

标签: java java.util.concurrent

根据JCIP的第6.3.2节:

  

Runnable是一个相当有限的抽象; run无法返回值或抛出已检查的异常。

run()无法返回值,因为它的返回类型为void但为什么不能抛出已检查的异常?

6 个答案:

答案 0 :(得分:22)

它不会抛出一个已检查的异常,因为它没有被声明为从第一个版本抛出一个已检查的异常,而且更改它太危险了。

最初Runnable仅在包装的Thread中使用,并且假设开发人员希望捕获所有已检查的异常并处理它们,而不是将它们记录到System.err

当您可以将单个任务添加到Callable时,可以添加

Executor,您可以在Future中捕获结果并抛出任何异常。

Callable现在允许您返回一个值,并且可选地声明一个已检查的异常。

BTW :你可以说你不希望从可调用者返回或抛出已检查异常的一种方法是使用

之类的东西
Callable<Void> callable = new Callable<Void>() {
    public Void call() {
        // do something
        return null;
    }
};

答案 1 :(得分:5)

这不是问题的答案。相反,它是Lukas Eder's answer的后续,显示了另一种将已检查的异常走私到不是静态允许的地方的方法。这取决于如果使用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伏都教。不要这样做。除了聚会给人们留下深刻印象。

答案 2 :(得分:4)

run()无法抛出已检查的异常,因为它未声明这样做。您无法在不声明的情况下抛出已检查的异常。

您也无法在覆盖或实现另一个不会抛出该异常的方法的方法上声明已检查的异常。因此,Runnable的实现只能将throws子句添加到run()的实现中。

答案 3 :(得分:2)

您总是可以不安全地抛出已检查的例外:

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

话虽如此,不要这样做! ; - )

答案 4 :(得分:2)

如果查看Runnable Interface,您会发现void run()方法未被声明为抛出任何已检查的异常,而您的Thread类实现了Runnable Interface。

JLS表示如果在Interface / Superclass中没有声明它,方法m1不会抛出异常。

答案 5 :(得分:2)

我认为在Runnable中保留签名void run()背后的动机是它不像其他方法那样被调用,而是设计为由CPU线程调度程序调用。如果是这样,谁将接收其返回值以及谁将要处理抛出的已检查异常。 {5.0}来自Java 5.0来处理Thread抛出的未捕获的异常。 Executor Framework将返回值或抛出的异常(ExecutionException中的包装器)保存为跨线程(如外层类实例)共享的某些Object的状态,并向Future调用那些调用者(在其他线程中运行)。{{ 3}}()。