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.
3 odpowiedzi
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)
nafuturesList.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);
}
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.
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).
Podobne pytania
Nowe pytania
java
Java to język programowania wysokiego poziomu. Użyj tego tagu, jeśli masz problemy z używaniem lub zrozumieniem samego języka. Ten tag jest rzadko używany samodzielnie i jest najczęściej używany w połączeniu z [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] i [maven].