21

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 ?

Tom Anderson
  • 46,189
  • 17
  • 92
  • 133
Inquisitive
  • 7,476
  • 14
  • 50
  • 61

6 Answers6

31

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;
    }
};
AdrieanKhisbe
  • 3,899
  • 8
  • 37
  • 45
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    "Too dangerous" == would break compatibility for hundreds of thousands of existing programs. That is a big "no no"!! – Stephen C Jul 10 '12 at 09:18
  • @peter Callable only says the return from the call is of type void ? Does it say anything at all for exceptions that can be thrown from call ()? – Inquisitive Jul 10 '12 at 09:22
  • The fact that there is no `throws` clause states there are no check exceptions. Even if the parent declares `throws Exception` doesn't mean the child has to. However if the parent does not "throws" a checked exception, the child cannot throw a checked exception. – Peter Lawrey Jul 10 '12 at 09:39
  • @PeterLawrey I got the point why runnable can not throw a checked exception . But my question in my earlier commment was what does Callable indicate to the users ? Does it not simply say that this callable doesn't return any value from it s call() method? Does it also say that no exceptions that can be thrown from call() method ? – Inquisitive Jul 10 '12 at 09:46
  • @Subhra That portion of the code doesn't say anything about whether checked exceptions can be thrown. You would have to read more of the code. – Peter Lawrey Jul 10 '12 at 09:55
  • @PeterLawrey I accepted your answer but what confused me was the line "BTW: One way you can say you don't want either from a callable is to use something like" . Specifically the word "either" was the point for confusion here. – Inquisitive Jul 10 '12 at 09:58
  • unfortunately Callable has that pesky return line, but it's close to being clean LOL – rogerdpack Feb 06 '13 at 19:06
  • +1; great answer. Just what I needed: a callable which didn't return a value. – Bathsheba Sep 13 '13 at 11:49
  • Hey Peter Thanks for the good reply ! request you please elaborate on this "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." – lowLatency Sep 18 '13 at 16:38
  • @Naroji Runnable isn't designed to throw checked exceptions, but Callable is. – Peter Lawrey Sep 18 '13 at 17:14
  • @PeterLawrey thanks , I agree with your point. but what I am looking is the thought process behind it (reason why these are designed like this) – lowLatency Sep 19 '13 at 09:28
  • @Naroji Checked exception are intended to be handled by the caller. For Runnable in Java 1.0, there was no common way to handle exception thrown out of run(). In Java 5.0, there is a way to submit a task and have it throw a checked exception, and you to handle it when you `get()` the result. – Peter Lawrey Sep 19 '13 at 09:43
5

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

Tom Anderson
  • 46,189
  • 17
  • 92
  • 133
  • 1
    What's especially confusing is that current docs for [invokeAndWait](http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#invokeAndWait%28java.lang.Runnable%29) discuss what happens "if the Runnable.run method throws an uncaught exception". I'm sure many people have read that and blithely tried to declare an exceptions clause for their overriding run()s. – Ti Strga Dec 14 '12 at 16:11
5

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.

Community
  • 1
  • 1
Tom Anderson
  • 46,189
  • 17
  • 92
  • 133
3

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

lab bhattacharjee
  • 1,617
  • 2
  • 17
  • 33
  • 3
    Precisely. As others said, it is obvious that the literal answer is "run() is not declared to throw anything," but I think the real question is why it is so. And the answer is, run() is meant to be called by a thread, which terminates or returns to a pool after run() returns, so who would catch it? Therefore there is never a case where throwing an exception would be useful. – Chad N B Sep 05 '13 at 04:09
2

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

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
2

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.

amicngh
  • 7,831
  • 3
  • 35
  • 54