我需要在并发线程中启动一堆任务并检索其结果。
这是我的代码:
List<Callable<? extends Object>> tasks = new ArrayList<>();
// Adding some tasks whith return different types of results:
// Callable<Double>, Callable<String>, Callable<SomeOtherType>, and so on...
List<Future<? extends Object>> results = executor.invokeAll( tasks );
但是IDE向我显示了下一个错误:
no suitable method found for invokeAll(List<Callable<? extends Object>>)
method ExecutorService.<T#1>invokeAll(Collection<? extends Callable<T#1>>)
is not applicable
(cannot infer type-variable(s) T#1
(argument mismatch; List<Callable<? extends Object>> cannot be converted
to Collection<? extends Callable<T#1>>
method ExecutorService.<T#2>invokeAll(Collection<? extends Callable<T#2>>,long,TimeUnit)
is not applicable
(cannot infer type-variable(s) T#2
(actual and formal argument lists differ in length))
where T#1,T#2 are type-variables:
T#1 extends Object declared in method
<T#1>invokeAll(Collection<? extends Callable<T#1>>)
T#2 extends Object declared in method
<T#2>invokeAll(Collection<? extends Callable<T#2>>,long,TimeUnit)
方法签名为:
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
显然,我可以替换<? extends Object>
为<Object>
,并返回所有任务Object
(例如,替换SomeTask1 implements Callable<Double>
为SomeTask1 implements Callable<Object>
)。
但是我的问题是:为什么会发生此错误?我不明白为什么我不能这样编码。谁能说清楚?
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
这表示存在一个类型变量T
,使得参数为Collection<? extends Callable<T>>
。即,此方法签名假定列表中的所有Callables具有相同的type参数。您的列表不是这种情况,这就是编译器拒绝您的代码的原因。
api方法应该声明如下:
<T> List<Future<? extends T>> invokeAll(Collection<? extends Callable<? extends T>> tasks);
在Java中设计通用API时,这是一个众所周知的陷阱。缺少声明站点协方差(这将允许声明状态Callable<String>
为的子类型Callable<Object>
)要求在通用类型的每次使用时都使用通配符类型指定协方差。也就是说,API永远不要编写Callable<T>
,而应该始终编写Callable<? extends T>
。当然,如本例所示,这是多余的并且容易忘记。
在您的特定情况下,最好这样做:
List<Future<?>> futures = new ArrayList<>();
for (Callable<?> callable : tasks) {
futures.add(executor.submit(callable));
}
for (Future<?> future : futures) {
future.get();
}
如果您不止一次需要这样做,可以将其放入实用程序方法中,并牢记使用适当的签名;-)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句