I get a compilation error when using generics
i write the following code:
public void test() {
Callable<?> myCall = new Callable() {
@Override
public String call() throws Exception {
return doDomething();
}
};
Callable<?> myCall2 = new Callable() {
@Override
public String call() throws Exception {
return doDomething2();
}
};
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Future<?>> futuresList = executor.invokeAll((Collection<? extends Callable<?>>) getList());
String result1 = futuresList.get(0).get();
String result2 = futuresList.get(0).get();
...
...
}
private List<Callable<?>> getList() {
.. create callables with wildcard and return them
}
i get the following compilation error: The method invokeAll(Collection>) in the type ExecutorService is not applicable for the arguments (Collection>).
EDI开发者_如何学JAVAT i added a method getList because i want this to use generics and not String. I want to understand why it doesnt compile. and in my real program it is a method.
You have to understand when you need wildcards in generics. In your example, you don't need them at all. You only need them when you don't know the type of some generic object. In your example, you want the Callables to return Strings so you should use as your generic type, like this:
public void test() throws InterruptedException, ExecutionException {
Callable<String> myCall = new Callable<String>(){
public String call() throws Exception{
return doDomething();
}
};
Callable<String> myCall2 = new Callable<String>(){
public String call() throws Exception{
return doDomething2();
}
};
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Callable<String>> list = Arrays.asList(myCall, myCall2);
List<Future<String>> futuresList = executor.invokeAll(list);
String result1 = futuresList.get(0).get();
String result2 = futuresList.get(1).get();
executor.shutdown();
}
See Sun's / Oracle's tutorial on generics and wildcards
EDIT:
- changed
futuresList.get(0)
tofuturesList.get(1)
to get the second result - added
executor.shutdown()
because people tend to forget this...
EDIT2:
Responding to your comment, here is another example. That's one way you could do stuff like this. I want to show how you have to generify all involved method from the caller all the way down inside your Callables or better your doDomething
methods.
public void test() throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Callable<String>> list = getList();
List<Future<String>> futuresList = executor.invokeAll(list);
String result1 = futuresList.get(0).get();
String result2 = futuresList.get(1).get();
System.out.println(result1);
System.out.println(result2);
executor.shutdown();
}
private <T> List<Callable<T>> getList() {
Callable<T> myCall = new Callable<T>(){
public T call() throws Exception{
return (T) "a"; //doDomething();
}
};
Callable<T> myCall2 = new Callable<T>(){
public T call() throws Exception{
return (T) "b"; //doDomething2();
}
};
return Arrays.asList(myCall, myCall2);
}
Remove the cast in the line with invokeAll()
, and change your unbound wildcards (?
) with String
. This doesn't compile, and its possible but hard to explain exactly why, but, since you really intend to operate on String
, just say so and it works.
I agree with the other answers posted - you should just be parameterising on String
rather than a wildcard.
If you want to know why the wildcards aren't working as you expect, Angelika Langer's excellent Java Generics FAQ has a section on repeating wildcard declarations which covers this (it's the second example).
精彩评论