3

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

Community
  • 1
  • 1
Acewin
  • 1,657
  • 4
  • 17
  • 36

1 Answers1

2

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();
}
Acewin
  • 1,657
  • 4
  • 17
  • 36
diesieben07
  • 1,487
  • 1
  • 14
  • 25
  • thanks for the response. Above statement construct being fine I still do not get how to rectify the final statement List> futures = executorService.invokeAll(executedCallables); – Acewin Dec 01 '16 at 23:37
  • 1
    You won't get out a `List>`, you will get a `List>`. There is no way to make the `T` a wildcard here. – diesieben07 Dec 01 '16 at 23:38
  • This compiles fine for me: `Callable foo = () -> ""; Set> set = new HashSet<>(); set.add(foo::call); ExecutorService service = null; // put something proper here List> futures = service.invokeAll(set);` – diesieben07 Dec 01 '16 at 23:42
  • 1
    I realized I was not checking the final error is for unhandled exception. Already marked this as correct solution – Acewin Dec 01 '16 at 23:44
  • It's always the little things :D – diesieben07 Dec 01 '16 at 23:44