I am implementing some code using java.util.concurrency framework. I will pass a set of called materials to a class that will execute them in parallel. I am trying to devise a better way to keep each answer a safe type. Here is the code to help explain what I'm doing:
First, I create my Callable s, which are units of work that will be called in parallel. For example, here the first unit of work returns a String , and the second a Integer :
Callable<String> firstCallable = new Callable<String>(){ public String call() {...} }; Callable<Integer> secondCallable = new Callable<Integer>(){ public Integer call() {...} };
Now I run them in my framework to run them in parallel, and the trick gets a handle to the appropriate response object. Here's an implementation that works:
Map<Callable,Object> responseMap = ParallelSender.send(firstCallable, secondCallable);
where Object is the response of a particular Callable . So you can do this:
String firstCallableResponse = (String)responseMap.get(firstCallable); Integer secondCallableResponse = (Integer)responseMap.get(secondCallable);
So my question is: is it possible to avoid casting when removing a card? This does not compile, but I think along these lines:
Map<Callable<T>, T> responseMap = ParallelSender.send(...); String firstCallableResponse = responseMap.get(firstCallable);
so the return value is based on the typed parameter of the Callable key. My concern is that if someone reorganizes the return type of unit of work (say from Integer to BigDecimal or something else), the cast from Object will never be caught by automatic refactoring tools and may lead to runtime problems.
CONCLUSION: thanks to all the useful comments and discussion below, I took a slightly different tact (although Sean Patrick Floyd was credited with my correct question above). I ended up completely Callable the response card and running the Callable object with the answer. Here are the relevant code snippets:
public abstract class AbstractParallelCallable<V> implements Callable<V> { private V callableResponse; public V getResponse() { return callableResponse; } public void setResponse(V response) { callableResponse = response; } }
That way, I have an abstract implementation that wraps a Callable object, storing the response. Then, in my parallel processing, I get the answer created by each Future and populating AbstractParallelCallable:
for (ParallelFutureTask<Object> future : futures) { try { future.getCallableHandle().setResponse(future.get()); } catch(Exception e) {...} }
where getCallableHandle returns an AbstractParallelCallable and ParallelFutureTask wrappers FutureTask object, providing a reference to the Callable object. After execution, the call code can then do this:
Integer theResult = firstCallable.getResponse();