(替代
my original answer)
但是,如果转型是缓慢的,或者某些输入可能会失败但是对其他输入成功会怎么样?在这种情况下,我们希望单独转换每个输出.另外,我们希望确保转换只发生一次.我们的集合转换方法不能保证这一点.因此,在您的示例代码中,输出上的每次迭代都会向执行程序提交新任务,即使先前提交的任务可能已经完成.因此,只有在转换是轻量级的时候,我们才推荐Iterables.transform和朋友. (通常,如果你正在做重量级的事情,你的转换函数将抛出一个已检查的异常,函数不允许.考虑这个提示:)当然,你的例子不会触发提示.)
这在代码中意味着什么?基本上,我们将颠倒我在其他答案中给出的操作顺序.我们将转换为Future< Iterable< A>>到Iterable< Future< A>>第一.然后我们将为每个A提交一个单独的任务,将其转换为B.对于后一步,我们将提供Executor so that the transformation doesn’t block some innocent thread.(我们现在只需要Futures.transform,所以我静态导入它. )
List> individuals = newArrayList();
for (int i = 0; i < knownSize; i++) {
final int index = i;
individuals.add(transform(input,new Function,A>() {
@Override
public A apply(List values) {
return values.get(index);
}
}));
}
List> result = newArrayList();
for (ListenableFuture original : individuals) {
result.add(transform(original,function,executor));
}
return result;
无论如何,那就是这个想法.但我的实施是愚蠢的.我们可以轻松地同时执行这两个步骤:
List> result = newArrayList();
for (int i = 0; i < knownSize; i++) {
final int index = i;
result.add(transform(input,B>() {
@Override
public B apply(List values) {
return function.apply(values.get(index));
}
},executor));
}
return result;
因为这使得n Futures.transform调用而不是1并且因为它使用单独的Executor,所以如果转换是重量级的,那么它比我的其他解决方案更好,如果它是轻量级的则更糟.另一个警告仍然是:只有当你知道你将拥有多少输出时,这才有效.