2013-08-28 4 views
1

Я пытаюсь использовать неограниченные подстановочные знаки, потому что у меня есть некоторые Callable, которые возвращают Object, но меня не интересует объект (они возвращают null, и я просто использую Callable вместо Runnable to быть в состоянии бросить проверенные Исключения).Правильное использование неограниченных генериков wilcard

Таким образом, в принципе, я хочу сделать это:

CompletionService<?> ecs = ... 
Callable<?> = ... 
Future<?> f = ecs.submit(c); 

Но здесь я получаю сообщение об ошибке сказав:

Метод submit(Callable<capture#1-of ?>) в типе CompletionService<capture#1-of ?> не применяется для аргументов (Callable<capture#2-of ?>)

Позже я просто хочу позвонить f.get() для обработки исключений, отправленных в заданную задачу.

Итак, каков правильный способ справиться с этим?

ответ

4

Подстановочные знаки здесь не подходят. (Также обратите внимание, что если у вас есть две маски они не совпадают с таковыми, так же, как если у вас есть общие параметры, названные T и U.)

Стандартный подход заключается в использовании <Void>.

+0

'Void' хорошо. Это фактически гарантирует во время компиляции, что ваш метод возвращает 'null' (и ничего больше). – Thilo

+0

Да, это именно то, что я искал.Никогда не слышал об этом раньше. – bennihepp

0

попробовать это

CompletionService<Object> ecs = ...; 
    Callable<Object> c = ...; 
    Future<?> f = ecs.submit(c); 
0

Проблема здесь состоит в том, что ? не является идентификатором. Это означает «что-то неизвестное». Первое «нечто неизвестное» - это не то, что второе. Другими словами, подумайте, что вы хотите отправить Callable<C> в CompletionService<S>. Очевидно, что это не сработает.

Путь решения этой проблемы либо использовать Object в качестве универсального типа:

CompletionService<?> ecs = ... 
Callable<?> = ... 
Future<?> f = ecs.submit(c); 

или, возможно, лучше, определить свой собственный тип T на уровне метода и использовать его в коде:

<T> void foo() { 
    CompletionService<T> ecs = ... 
    Callable<T> = ... 
    Future<?> f = ecs.submit(c); 
} 

вы, вероятно, получите войну в строке CompletionService<T> ecs = ..., но вы можете ее подавить (только здесь). Остальная часть кода должна быть в порядке.

Эта рекомендация, однако, не звучит как хорошая практика. Дженерики были добавлены на язык программирования Java, чтобы решить проблему неизвестных типов. Таким образом, лучший способ - правильно использовать генерики в целом.

0

Вам нужна переменная типа, чтобы объявить, что параметры типа всех объектов совпадают, даже если вы не интересуетесь самим типом. Чтобы объявить переменную типа, вы должны поместить код внутри метода или конструктора, который может объявить его, например.

static <T> Future<T> doIt(Callable<T> c, Executor e) { 
    CompletionService<T> ecs = new ExecutorCompletionService<T>(e); 
    return ecs.submit(c); 
} 

Теперь вы можете даже назвать это с групповыми символами:

Callable<?> c; 
Executor e; 
Future<?> f=doIt(c, e); 
Смежные вопросы