Piszę następujący kod:

 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
}

Otrzymuję następujący błąd kompilacji: Metoda invokeAll(Collection>) w typie ExecutorService nie ma zastosowania do argumentów (Collection>).

EDIT Dodałem metodę getList, ponieważ chcę, aby używała generyków, a nie String. Chcę zrozumieć, dlaczego się nie kompiluje. aw moim prawdziwym programie jest to metoda.

1
AAaa 22 czerwiec 2011, 12:11

3 odpowiedzi

Najlepsza odpowiedź

Musisz zrozumieć, kiedy potrzebujesz symboli wieloznacznych w rodzajach. W twoim przykładzie wcale ich nie potrzebujesz. Potrzebujesz ich tylko wtedy, gdy nie znasz typu jakiegoś ogólnego obiektu. W twoim przykładzie chcesz, aby Callables zwracały ciągi znaków, więc powinieneś użyć jako swojego typu ogólnego, na przykład:

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

Zobacz samouczek dotyczący kodów generycznych i symboli wieloznacznych firmy Sun / Oracle

EDYTUJ:

  • zmieniono futuresList.get(0) na futuresList.get(1), aby uzyskać drugi wynik
  • dodano executor.shutdown(), ponieważ ludzie często o tym zapominają...

EDYCJA2:

Odpowiadając na Twój komentarz, oto kolejny przykład. To jeden ze sposobów, w jaki możesz robić takie rzeczy. Chcę pokazać, w jaki sposób należy wygenerować wszystkie zaangażowane metody od wywołującego aż w dół w swoich Callables lub ulepszyć metody doDomething.

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);
}
4
Tim Büthe 22 czerwiec 2011, 13:30
Zredagowałem moje pytanie. Wiem, że w tym przykładzie mogę użyć String. ale mój prawdziwy program jest bardziej ogólny. Muszę użyć symbolu wieloznacznego.
 – 
AAaa
22 czerwiec 2011, 12:48
Dodałem kolejny przykład. Ten przykład zawiera rzutowanie, co nie powinno być konieczne, jeśli robisz generyki do końca. Jednak od czasu do czasu potrzebuję rzutu, może ktoś inny podpowie, jak zoptymalizować przykład.
 – 
Tim Büthe
22 czerwiec 2011, 13:37
Dziękuję. czy dobrze rozumiem, że musimy użyć tutaj generycznego i bez symboli wieloznacznych, tylko dlatego, że metoda invokeAll jest napisana z użyciem generycznego, a nie wieloznacznego?
 – 
AAaa
22 czerwiec 2011, 18:37
@dan: Musisz myśleć o typie wieloznacznym, bardziej jako o abstrakcyjnej rzeczy. Odbiorca może chcieć wyrazić coś w stylu „daj mi jakiś pojazd, nie obchodzi mnie, czy to samochód, czy autobus”. Może to być napisane jako "Lista". Dzwoniący ma jakąś konkretną Listę, np. List i może to przekazać.
 – 
Tim Büthe
27 czerwiec 2011, 12:05

Usuń obsadę w linii za pomocą invokeAll() i zmień niezwiązane symbole wieloznaczne (?) za pomocą String. To się nie kompiluje i jest to możliwe, ale trudno dokładnie wyjaśnić, dlaczego, ale ponieważ naprawdę zamierzasz operować na String, po prostu powiedz to i działa.

0
Sean Owen 22 czerwiec 2011, 12:18
Zredagowałem pytanie. nie zamierzam pracować tylko z ciągiem.
 – 
AAaa
22 czerwiec 2011, 12:49

Zgadzam się z innymi opublikowanymi odpowiedziami – powinieneś po prostu ustawić parametry na String, a nie za pomocą symbolu wieloznacznego.

Jeśli chcesz wiedzieć, dlaczego symbole wieloznaczne nie działają zgodnie z oczekiwaniami, doskonałe FAQ na temat Java Generics Angeliki Langer zawiera sekcję powtarzające się deklaracje symboli wieloznacznych, które obejmują to (jest to drugi przykład).

0
Community 23 maj 2017, 14:48