Is there a solution to my problem using generics?

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> { /** The response generated by the Call method of this class. */ 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(); 
+3
source share
4 answers

Method approach

The only way to do this is to encapsulate it in a method:

 class ParallelSender{ private final Map<Callable<?>, Object> map = new HashMap<Callable<?>, Object>(); @SuppressWarnings("unchecked") public <T> T getResult(final Callable<T> callable){ return (T) map.get(callable); } } 

Client code

Now your client code is not required:

 ParallelSender parallelSender = new ParallelSender(); Callable<Integer> integerCallable = new Callable<Integer>(){ @Override public Integer call() throws Exception{ return Integer.valueOf(1); } }; Integer result = parallelSender.getResult(integerCallable); 
+8
source

Quick answer: No, you cannot store several types on a Map without going around them with the same parent type (for example, Object). You also do not want this to be possible. I would think about rethinking your design here. Do you really need you to respond to the map object? I assume you will get the values ​​from the map again again.

I would probably use a callback mechanism. Once Callable is completed, it saves the answer locally. When ParralelSender has sent everything (provided that it returns all Callable results in one go), iterates through each Callable and tells the registered listener to process the result.

Not sure if I make sense there, by the way. I would try to come up with an example, but lazy.

+1
source

IF all your answers are of the same type, then there is a solution.

 Map<Callable<String>,String> responseMap = ParallelSender.send(firstCallable, secondCallable); String firstCallableResponse = responseMap.get(firstCallable); 

But if you create different types of results on one map, and your code depends on their actual types, then no methods will help you.

0
source

Something like that:

 Callable<String> firstCallable = new Callable<String>(){ public String call() {...} }; Callable<Integer> secondCallable = new Callable<Integer>(){ public Integer call() {...} }; class ParallelSender { ParallelResults send(Callable<Object> o,...) {...} } class Parallelresults { T <T> get(Callable<T> key) { ... } } ParallelResults res = ParallelSender.send(firstCallable, secondCallable); String s = res.get(firstCallable); Integer i = res.get(secondCallable); 

You may need to throw in the get method.

0
source

Source: https://habr.com/ru/post/1336109/


All Articles