Recently coming across the subject I remembered that already questioned it in the past. While this seems obvious at first glance there is still something to clarify.
Depending on the context, in some cases, adding throws declaration to the run method would be convenient since something exceptional may still happen and the code in the run method often doesn’t know how to handle it. We would rather propagate the exception up to the caller. On the other hand the thread that actually calls the run method doesn’t know what to do with this information either. What it means is that since exception handling is rather application specific we would need to implement some special logic on top of Runnables and Threads. Well, so far so clear.
Why then Callable has throws declaration? This interface was added in 1.5 along with Executors and Futures. So Future is the answer. We cannot use Callables the way we use Runnables. We need to pass an instance of Callable to Executor which returns the Future object. An exception thrown in the call method is kindly stored in the Future instance and so it can be retrieved later. Future is the bit that was missing in communicaton between Runnables and Threads. What was confusing me in Future and why I was actually looking into using Runnables is that it has to return a value. If we have nothing to compute we have to use Void as its type paratemer and return null. This doesn’t look perfect but acceptable.