我已经阅读了之前关于此事的一些帖子。参数是列表更容易使用,更灵活。
我之前的所有经验都向我展示了灵活性是一种成本。
我正在设计的程序大量使用列表。我有映射到列表的列表,这些列表被比较,追加和搜索(哦,我的!)。
很容易附加两个列表。 listA.appendAll(数组listB)。
几乎同样容易追加两个数组。只需创建一个两者大小的新数组并复制它们。
现在,当这些操作按照成千上万的顺序完成时,我的直觉告诉我,阵列将是一个相当不错的选择。当然,我更倾向于使用列表,但不是以牺牲性能为代价
我的直觉本能是正确的,还是真正像数组一样有效的列表?我理解ArrayLists如何使容量增加一倍来增加平均值~O(N),但我需要最有效的选择。
答案 0 :(得分:8)
你的直觉几乎总是错误的(如果你肯定知道,你不需要听你的胆量,如果你不知道,你的决定大多是随机的。)
今天的问题不在于列表的效率如何,问题是:您需要多少内存以及您可以分配多少时间来寻找优化(但遗憾的是稍微损坏)代码中的错误?
数百万人正在使用ArrayList
,这是一种安全,经过验证,快速可靠的技术。添加其中两个几乎与使用两个本机数组手动执行速度一样快但是a)它只是 me 的一行代码,b)它涵盖了所有角落情况和c)是否应该真的太慢了,我可以让我的探测器找到一些太慢而且修复它们的地方(而不是让我的生活在一千个不太重要的地方让我痛苦不堪)。
除此之外,由于ArrayList
是如此繁重的使用类型,因此Java编译器和JIT已针对死亡进行了优化以使其快速生成。因此,即使它看起来更像是代码,它实际上可能比你手动编写的任何代码都要快,因为JIT无法识别你的代码并将其优化为积极的代码。
最后,您可以轻松编写自己的ArrayList
以使用更有效的分配算法。如果您在任何地方使用List
界面编写代码,最终只能在一个地方优化您需要的内容,以便在任何地方都能更快地完成。
或者可以使用新的Array接口以及您需要的2-3个操作。这样,您可以轻松创建2-3个不同优化目标的实现,并相应地使用它们。
根据我的经验,最糟糕的解决方案是将代码洒入4-10行本机阵列操作(比如需要附加两个数组的四行)。至少在公共帮助程序类中移动此类代码,并确保使用单元测试覆盖所有角落情况。
答案 1 :(得分:2)
我的直觉本能是正确的,还是真正像数组一样有效的列表?
两者都没有。列表并不像Arrays那样“真正”有效(尽管ArrayLists很接近),但这并不意味着任何优化都必然会超过灵活性的好处,即使你有数千个操作正在进行
考虑以下问题:
如果这两个问题的答案都是是,那么请使用数组。否则,请使用列表。
但是由于数组和列表之间的性能(特别是ArrayList实现)并没有那么多,并且因为你的代码很可能进一步开发......
... 只使用列表。
答案 2 :(得分:1)
ArrayList由数组支持,所以没有测试我觉得它们的效率可能很接近。如果您知道数组的大小,只需使用初始大小构造ArrayList
,以减少增加大小的开销。
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
this.elementData = new Object[initialCapacity];
}
ArrayList.addAll
ArrayList实现看起来像你可能想出的东西
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
奇怪的是,如果你自己制作数组,你可能会最终制作一个辅助方法来完成ArrayList
已经实现的大部分内容。不要重新发明轮子