Why cannot run() of Runnable throw checked Excepti

2020-06-08 16:58发布

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 ?

6条回答
够拽才男人
2楼-- · 2020-06-08 17:37

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().

查看更多
▲ chillily
3楼-- · 2020-06-08 17:39

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.

查看更多
做自己的国王
4楼-- · 2020-06-08 17:45

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楼-- · 2020-06-08 17:48

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;
    }
};
查看更多
趁早两清
6楼-- · 2020-06-08 17:49

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().

查看更多
甜甜的少女心
7楼-- · 2020-06-08 17:52

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! ;-)

查看更多
登录 后发表回答