开发者

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) to futuresList.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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜