【发布时间】:2012-07-10 09:08:15
【问题描述】:
根据JCIP 的第 6.3.2 节:
Runnable 是一个相当有限的抽象; run 不能返回值或抛出检查异常。
run() 不能返回一个值,因为它的返回类型是 void 但为什么不能抛出一个检查异常?
【问题讨论】:
-
如果需要返回值最好在ExecutorService中使用Callable接口
-
Err,因为它被声明不是这样吗?
根据JCIP 的第 6.3.2 节:
Runnable 是一个相当有限的抽象; run 不能返回值或抛出检查异常。
run() 不能返回一个值,因为它的返回类型是 void 但为什么不能抛出一个检查异常?
【问题讨论】:
它不能抛出已检查的异常,因为从第一个版本开始它没有被声明为抛出已检查的异常,更改它太危险了。
最初Runnable 仅在包装后的Thread 中使用,并且假设开发人员希望捕获所有已检查的异常并处理它们,而不是将它们记录到System.err。
当您可以将单个任务添加到Executor 时添加Callable,您可以在Future 中捕获结果并引发任何异常。
Callable 现在允许您返回一个值并可选择声明一个已检查的异常。
顺便说一句:您可以说您不希望从可调用对象返回或抛出已检查异常的一种方法是使用类似
Callable<Void> callable = new Callable<Void>() {
public Void call() {
// do something
return null;
}
};
【讨论】:
throws 子句的事实表明没有检查异常。即使父母声明throws Exception 并不意味着孩子必须这样做。但是,如果父级没有“抛出”已检查异常,则子级无法抛出已检查异常。
这不是问题的答案。相反,它是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();
}
}
这是 A 类真正古老的黑帽 Java 巫术。永远不要这样做。除了在派对上给人留下深刻印象。
【讨论】:
run() 不能抛出已检查异常,因为它没有声明这样做。你不能在不声明的情况下抛出已检查的异常。
您也不能在覆盖或实现另一个不会引发该异常的方法的方法上声明已检查异常。因此,Runnable 的实现不能简单地将throws 子句添加到它们的run() 实现中。
【讨论】:
如果您查看Runnable Interface,您会发现void run() 方法未声明为抛出任何已检查的异常,并且您的 Thread 类实现了 Runnable 接口。
JLS 表示如果在接口/超类中未声明方法 m1,则它不能抛出异常。
【讨论】:
我认为在 Runnable 中保留签名 void run() 背后的动机是,它并不像其他方法那样被调用,而是被设计为由 CPU 线程调度程序调用。如果是这样,谁将接收它的返回值,谁将处理由此引发的检查异常。 UncaughtExceptionHandler 出现在 Java 5.0 中,用于处理线程抛出的未捕获异常。 Executor Framework 将返回的值或抛出的异常(ExecutionException 中的包装器)保存为跨线程(如 Outer 类实例)共享的某些 Object 的状态,并将这些状态提供给 Future 的调用者(在其他线程中运行)。@987654322 @()。
【讨论】:
你总是可以不安全地抛出已检查的异常:
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
话虽如此,但不要这样做! ;-)
【讨论】:
Unsafe。从无参数构造函数抛出的已检查异常会转义 newInstance 调用。我会添加一个答案...