1

From this answer I learned that the only difference between Callable and Runnable is that former can return a result of the execution and throw an exception.

I don't understand why Executor doesn't define a method which takes a Callable:

void execute(Callable command);

From my point of view, it'd be logical to create methods for both Runnable and Callable. In ExecutorService, which is a subinterface of Executor, there are similar submit() methods for both Runnable and Callable.

Please, explain this design decision, because I can't find any explanation on the Internet.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
Artem Malchenko
  • 2,320
  • 1
  • 18
  • 39
  • if you really want to know that, you shouldn't be asking this on an open forum, but at those who actually designed it – Stultuske Nov 22 '17 at 11:51

3 Answers3

2

I suppose the Executor design was meant to be as simple as possible, i.e. with one method. Since execute() doesn't provide any means of getting the result, it makes sense that it doesn't accept Callables, and takes only Runnables.

On the other hand, the various submit() functions return Futures, which can be used to both obtain a result (e.g. from a Callable), or to simply wait for the execution to finish. So, it makes sense to accept both Runnable and Callable.

xs0
  • 2,990
  • 17
  • 25
2

Executors run tasks. They are needed if you want to manage how and when tasks should be run. Executors don't collect task results and thus support only Runnable.

Assume they support Callable. Then how should one fetch the result? T execute(Callable<T> command) is not an option as it will block current thread execution. So it should be paired with some T getResult() or return Future<T>. And for that you have ExecutorService with method <T> Future<T> submit(Callable<T> task).

AlexZam
  • 1,147
  • 7
  • 18
2

I don't understand why Executor doesn't define a method which takes a Callable.

An Executor has a single responsibility - executing a submitted task. On this abstraction level, APIs that use only Runnables don't demand the additional features proposed by the ExecutorService.

It'd be logical to create methods for both Runnable and Callable.

Yes, therefore the ExecutorService interface was designed by extending the Executor. The ExecutorService offers a significant difference - providing results of task execution. That's why the Callable, TimeUnit, and lifecycle methods were added.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142