Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collection of Callable and Generics

Tags:

java

generics

I need to launch a bunch of tasks in concurrent threads and retrieve its results.

Here is my code:

List<Callable<? extends Object>> tasks = new ArrayList<>();

// Adding some tasks whith return different types of results:
// Callable<Double>, Callable<String>, Callable<SomeOtherType>, and so on...

List<Future<? extends Object>> results = executor.invokeAll( tasks );

But the IDE shows me the next error:

no suitable method found for invokeAll(List<Callable<? extends Object>>)

    method ExecutorService.<T#1>invokeAll(Collection<? extends Callable<T#1>>)
            is not applicable
      (cannot infer type-variable(s) T#1
        (argument mismatch; List<Callable<? extends Object>> cannot be converted
                to Collection<? extends Callable<T#1>>

    method ExecutorService.<T#2>invokeAll(Collection<? extends Callable<T#2>>,long,TimeUnit)
            is not applicable
      (cannot infer type-variable(s) T#2
        (actual and formal argument lists differ in length))

  where T#1,T#2 are type-variables:
    T#1 extends Object declared in method
            <T#1>invokeAll(Collection<? extends Callable<T#1>>)
    T#2 extends Object declared in method
            <T#2>invokeAll(Collection<? extends Callable<T#2>>,long,TimeUnit)

The method signature is:

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)

Obviously, I can replace <? extends Object> with <Object>, and make all of my tasks return Object (e.g. replace SomeTask1 implements Callable<Double> with SomeTask1 implements Callable<Object>).

But my question is: why this error occurs? I do not understand why I can't code like this. Can anyone make it clear?

like image 414
user1764823 Avatar asked May 21 '14 11:05

user1764823


People also ask

What is Callable method?

Interface Callable<V>A task that returns a result and may throw an exception. Implementors define a single method with no arguments called call. The Callable interface is similar to Runnable , in that both are designed for classes whose instances are potentially executed by another thread.

What is the use of Callable in Java?

The callable interface was introduced in concurrency package, which is similar to the Runnable interface, but it can return any object, and is able to throw an Exception. The Java Callable interface uses Generics, so it can return any type of Object.

What is Callable and future in Java?

Observe that Callable and Future do two different things – Callable is similar to Runnable, in that it encapsulates a task that is meant to run on another thread, whereas a Future is used to store a result obtained from a different thread.


1 Answers

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)

This says that there is a type variable T such that the argument is a Collection<? extends Callable<T>>. That is, this method signature assumes that all Callables in the list have the same type argument. That's not the case for your list, which is why the compiler rejects your code.

The api method should have been declared as follows:

<T> List<Future<? extends T>> invokeAll(Collection<? extends Callable<? extends T>> tasks);

This is a well known pitfall when designing generic APIs in Java. The absence of declaration site covariance (which would allow one to state that Callable<String> is a subtype of Callable<Object>) requires the specification of covariance with a wildcard type at every usage of the generic type. That is, an API should never write Callable<T>, but always Callable<? extends T>. Of course, that's redundant and easy to forget, as this example shows.

In your particular case, it's probably best to do:

List<Future<?>> futures = new ArrayList<>();
for (Callable<?> callable : tasks) {
     futures.add(executor.submit(callable));
}
for (Future<?> future : futures) {
    future.get();
}

if you need this more than once, you can put it into a utility method, keeping in mind to use the proper signature ;-)

like image 123
meriton Avatar answered Sep 20 '22 15:09

meriton