Guava使用的经验和教训
1.com.google.common.collect.Lists#transform(List<T> originList,Function function)
由于Lists.transform是延迟调用,返回的其实是originList的view,也就是当客户端遍历生成的列表时,给定的Function应用到originList的元素上,而且每一次遍历生成的列表都会重新应用一次。
核心代码
@Override
public Iterator<T> iterator() {
return listIterator();
}
@Override
public ListIterator<T> listIterator(int index) {
return new TransformedListIterator<F, T>(fromList.listIterator(index)) {
@Override
T transform(F from) {
return function.apply(from);
}
};
}
错误的使用场景
1. 通过线程池执行Callable任务,任务的返回结果是通过Lists.transform来完成的
错误代码示例
@Override
public List<XXX> call() {
return Lists.transform(Safes.of(list), new Function<P, XXX>() {
@Override
public ResultWrapper<R> apply(P input) {
return fun.apply(input);
}
});
}
通常我们的使用场景是在主线程中创建任务,然后将任务提交到ThreadPool中,然后获取Future,在主线程中调用Future.get(),然后处理结果。但是由于上述的错误示例,发现代码的逻辑并没有并行执行,而是拿到结果后在遍历的串行执行的,这个就是因为Lists.transform的惰性调用导致并行化失败。
2.对Lists.transform的结果进行二次处理,然后执行集合求交集、差集等涉及到equals的操作
错误代码示例
List<XXX> result = Lists.transform();
List<XXX> subList = Lists.newArrayList();
for(XXX x:result){
if(true){
subList.add(x);
}
}
result = CollectionUtils.substract(result,subList);
然后会发现没有任何元素被移除,前提条件是XXX没有重写equals方法。
解决方法
问题的原因就是因为惰性加载导致的,所以如果Lists.transform后,可以对结果集进行一次copy(To avoid lazy evaluation when the returned list doesn't need to be a view, copy the returned list into a new list of your choosing.)
网友评论