问题
According to section 6.3.2 of JCIP :
Runnable is a fairly limiting abstraction; run can not return a value or throw checked exception .
run()
can not return a value since its return type is void but why can not it throw a checked exception ?
回答1:
It cannot throw a checked exception because it wasn't declared as throwing a checked exception from the first version and it is too dangerous to change it.
Originally Runnable
was only used in a wrapped Thread
, and it was assumed the developer would want to catch all checked exceptions and handle them rather than logging them to System.err
.
Callable
was added when you can add individual tasks to an Executor
where you can capture the result in a Future
and any exception thrown.
Callable
now allows you to return a value and optional declare a checked exception.
BTW: One way you can say you don't want a return or throw a checked exception from a callable is to use something like
Callable<Void> callable = new Callable<Void>() {
public Void call() {
// do something
return null;
}
};
回答2:
This is not an answer to the question. Rather, it is a followup to Lukas Eder's answer, showing another way to smuggle a checked exception into a place where it is not statically allowed. This relies on the fact that if a no-argument constructor is invoked with newInstance, any checked exception it throws escapes upward.
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();
}
}
This is class-A truly ancient black hat Java voodoo. Do not ever do this. Except at parties to impress people.
回答3:
run() can't throw a checked exception because it is not declared to do so. You can't throw checked exceptions without declaring them.
You also can't declare checked exceptions on a method which overrides or implements another method which doesn't throw that exception. So, implementations of Runnable
can't simply add throws
clauses to their implementations of run()
.
回答4:
If you look at the Runnable Interface you find that void run()
method is not declared as throwing any checked exception and your Thread class implements Runnable Interface .
JLS says that method m1 cannot throw exception if in Interface/Superclass it is not declared.
回答5:
I think the motivation behind keeping the signature void run() in Runnable is that it is not meant to be invoked like other methods, instead it is designed to be invoked by the CPU thread scheduler. If so, who is going to receive its return value and who is going to handle thrown checked exception by this. UncaughtExceptionHandler came in Java 5.0 to handle uncaught exceptions thrown by a Thread. The Executor Framework saves the returned value or thrown exception( wrapper in ExecutionException) as the states of some Object shared across threads(like Outer class instance) and purveys those to the invoker(who is running in some other thread) of Future.get().
回答6:
You can always unsafely throw checked exceptions:
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();
}
}
See the full article here:
http://java.dzone.com/articles/throwing-undeclared-checked.
Another alternative:
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;
}
}
This was shown here:
http://java.dzone.com/articles/throw-checked-exceptions
Having said so, don't do it! ;-)
来源:https://stackoverflow.com/questions/11410042/why-cannot-run-of-runnable-throw-checked-exceptions