Acewin Acewin - 8 days ago 9
Java Question

How to get the statement correct using generics

SO I am using ExecutorService and wanted to generate Callables so that I can execute them using invokeAll

The Callables have different return type. Which made me think I can get done using wild card

Set<Callable<?>> executedCallables = new HashSet<Callable<?>>();
executedCallables.add(serviceHelper.getOwnerDetails()); --> returns Callable<OwnerDetails>
executedCallables.add(iqmServiceHelper.getUserDetails()); --> returns Callable<UserDetails>


in similar fashion I added statement for invokeAll

List<Future<? extends Object>> futures = executorService.invokeAll(executedCallables);


ad this gives me compiler error
The method invokeAll(Collection<? extends Callable<T>>) in the type ExecutorService is not applicable for the arguments (Set<Callable<?>>)
which I am not getting how to resolve.

Can someone please point out the error in usage and correct usage.

Just a heads up the compiler error is from JDK 6. And I do not think is going to be different in higher version JDK

PS :- There is a similar StackOverflow thread as well on this Collection of Callable and Generics

Answer

The problem is that the signature of invokeAll is a bit too restrictive. It should be Collection<? extends Callable<? extends T>>, since the T is a producer here (remember from Effective Java: PECS - Producer Extends Consumer Super). However we of course cannot change a JDK method here, so we have to live with it. Solution is to pass in a Set<Callable<Object>> and either use an unsafe cast (which is safe, since you are only extracting values of type T out of the Callable) or to use a method reference:

Set<Callable<Object>> callables = new HashSet<>();
callables.add((Callable) serviceHelper.getOwnerDetails()); // method one
callables.add(iqmServiceHelper.getUserDetails()::call); // method two

The final statement will look like below

try {
    List<Future<Object>> futures = executorService.invokeAll(executedCallables);
} catch (InterruptedException e) {
    e.printStackTrace();
}