invokeAll() is not willing to accept a Collection<Callable<T>>

Yossale picture Yossale · Dec 16, 2008 · Viewed 9.4k times · Source

I fail to understand why this code won't compile

ExecutorService executor = new ScheduledThreadPoolExecutor(threads);

class DocFeeder implements Callable<Boolean> {....} 
... 
List<DocFeeder> list = new LinkedList<DocFeeder>();
list.add(new DocFeeder(1));
...
executor.invokeAll(list);

The error msg is:

The method invokeAll(Collection<Callable<T>>) in the type ExecutorService is 
not applicable for the arguments (List<DocFeeder>)  

list is a Collection of DocFeeder, which implements Callable<Boolean> - What is going on?!

Answer

Jon Skeet picture Jon Skeet · Dec 16, 2008

Just to expand on saua's answer a little...

In Java 5, the method was declared as:

invokeAll(Collection<Callable<T>> tasks) 

In Java 6, the method is declared as:

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

The wildcarding difference is very important - because List<DocFeeder> is a Collection<? extends Callable<T>> but it's not a Collection<Callable<T>>. Consider what would happen with this method:

public void addSomething(Collection<Callable<Boolean>> collection)
{
    collection.add(new SomeCallable<Boolean>());
}

That's legal - but it's clearly bad if you can call addSomething with a List<DocFeeder> as it will try to add a non-DocFeeder to the list.

So, if you are stuck with Java 5, you need to create a List<Callable<Boolean>> from your List<DocFeeder>.