Java 从Iterable创建列表时要使用哪个实现
我发现自己经常做以下事情:Java 从Iterable创建列表时要使用哪个实现,java,performance,list,memory-management,Java,Performance,List,Memory Management,我发现自己经常做以下事情: Iterator<A> itr = iterableOfA.getIterator(); List<B> list = new ArrayList<>(); // how about LinkedList? while (itr.hasNext()) { B obj = iter.next().getB(); list.add(obj); } someMethod(list); // this method take
Iterator<A> itr = iterableOfA.getIterator();
List<B> list = new ArrayList<>(); // how about LinkedList?
while (itr.hasNext()) {
B obj = iter.next().getB();
list.add(obj);
}
someMethod(list); // this method takes an Iterable
这意味着对iterableOfA
进行两次迭代。当iterable的大小未知且变化很大时,哪种选择最好:
ArrayList
LinkedList
iterableOfA
中的元素进行计数,并分配一个ArrayList
列表
是一种短期分配,因为在请求结束时,任何代码都不应包含对它的引用someMethod(list)
无法处理超过200个元素的iterable,因此我决定使用新的ArrayList(200)
,这对我来说已经足够好了
然而,在一般情况下,我更愿意实现公认答案中概述的解决方案(使用自定义iterable包装,避免分配列表的需要)
所有其他答案都提供了非常有价值的见解,让我们了解了ArrayList
与LinkedList
相比有多合适,因此我谨代表so社区感谢大家
当iterable的大小未知且变化很大时,哪种选择最好
这取决于你在优化什么
- 如果您正在优化性能,那么使用
可能会更快。即使ArrayList
需要调整备份阵列的大小,它也会使用指数增长模式进行调整。然而,这取决于迭代的开销ArrayList
<> L> > P>如果您对长期内存使用进行优化,请考虑使用<代码> ARAYLISTAB/COD> >其次是代码> Trimtosiz()/<代码> < /P>
- 如果您正在优化峰值内存使用,那么“计数优先”方法可能是最好的。(这假设您可以迭代两次。如果迭代器实际上是惰性计算的包装器……这可能是不可能的。)
- 如果您正在优化以减少GC,那么“计数优先”可能是最好的,这取决于迭代的细节
目前,如果
iterableOfA
有5000个元素,这将导致对列表的支持数组进行许多调整
ArrayList
类的大小调整为与当前大小成比例的新大小。这意味着调整大小的数量是O(logN)
,而N
列表附加调用的总成本是O(N)
当iterable的大小未知且变化很大时,哪种选择最好
这取决于你在优化什么
- 如果您正在优化性能,那么使用
可能会更快。即使ArrayList
需要调整备份阵列的大小,它也会使用指数增长模式进行调整。然而,这取决于迭代的开销ArrayList
<> L> > P>如果您对长期内存使用进行优化,请考虑使用<代码> ARAYLISTAB/COD> >其次是代码> Trimtosiz()/<代码> < /P>
- 如果您正在优化峰值内存使用,那么“计数优先”方法可能是最好的。(这假设您可以迭代两次。如果迭代器实际上是惰性计算的包装器……这可能是不可能的。)
- 如果您正在优化以减少GC,那么“计数优先”可能是最好的,这取决于迭代的细节
目前,如果
iterableOfA
有5000个元素,这将导致对列表的支持数组进行许多调整
ArrayList
类的大小调整为与当前大小成比例的新大小。这意味着调整大小的数量是O(logN)
,而N
列表附加调用的总成本是O(N)第三个选项不错。对于获取大小,大多数集合只返回它们内部维护的计数器…它不会遍历整个列表。这取决于实现,但所有java.util.xxx集合类都是这样做的
如果你知道“iterableOfA”的潜在类型,你可以检查它们的大小
如果“iterableOfA”是某种自定义实现,而您不确定大小是如何实现的,那么linkedlist会更安全。这是因为您的大小不同,并且调整大小的可能性更高,因此您将无法获得可预测的性能
也不确定您在填充“B”的集合中执行的操作,您的选择也取决于此。第三个选项不错。对于获取大小,大多数集合只返回它们内部维护的计数器…它不会遍历整个列表。这取决于实现,但所有java.util.xxx集合类都是这样做的
如果你知道“iterableOfA”的潜在类型,你可以检查它们的大小
如果“iterableOfA”是某种自定义实现,而您不确定大小是如何实现的,那么linkedlist会更安全。那是因为你的身材各不相同
Iterator<A> itr = iterableOfA.getIterator();
int size = Iterables.size(iterableOfA); // from Guava
List<B> list = new ArrayList<>(size);
// and the rest...
final Iterable<A> iofA ... ;
Iterable<B> iofB = new Iterable<B>() {
public Iterator<B> iterator() {
return new Iterator<B>() {
private final Iterator<A> _iter = iofA.iterator();
public boolean hasNext() { return _iter.hasNext(); }
public B next() { return _iter.next().getB(); }
};
}
};
for (Iterator<E> it = list.iterator(); it.hasNext(); ) {
E e = it.next();
if (someCondition(e)) e.remove();
}