AAaa
AAaa

Reputation: 3819

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

EDIT 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.

Upvotes: 1

Views: 318

Answers (3)

Tim B&#252;the
Tim B&#252;the

Reputation: 63734

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);
}

Upvotes: 4

Andrzej Doyle
Andrzej Doyle

Reputation: 103797

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

Upvotes: 0

Sean Owen
Sean Owen

Reputation: 66886

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.

Upvotes: 0

Related Questions