为什么不总是在Java中使用ArrayLists而不是普通的’数组?

这里有个简单的问题:为什么不总是在Java中使用ArrayLists? 除了额外的有用function之外,它们显然具有与arrays相同的访问速度。 我理解它不能保存原语的限制,但这可以通过使用包装器轻松减轻。

如果你需要一组基元,那么一个数组可能是这项工作的最佳工具。 拳击是一项相对昂贵的手术。 对于将用作基元的基元的集合(不包括地图),我几乎总是使用数组来避免重复装箱和拆箱。

但是,我很少担心数组和ArrayList之间的性能差异。 如果List将提供更好,更清晰,更易于维护的代码,那么我将始终使用List (或CollectionSet等,视情况而定,但您的问题是关于ArrayList ),除非有一些令人信服的理由不这样做。 表现很少是令人信服的理由。

使用Collection几乎总能产生更好的代码,部分原因是因为数组不能很好地使用generics,正如JohannesWeiß在评论中已经指出的那样,但也是因为有很多其他原因:

  • 集合具有非常丰富的API和各种各样的实现,可以(在大多数情况下)可以互相交换进出
  • 如果偶尔使用数组版本有用,则可以将Collection简单地转换为数组
  • 许多集合比数组增长更优雅,这可能是一个性能问题
  • 集合非常适用于generics,数组非常糟糕
  • 正如TofuBeer所指出的那样,数组协方差很奇怪,并且可以以无法实现的方式执行任何对象都不会起作用。集合以预期的方式处理协方差。
  • 数组需要根据其任务手动resize,如果数组未满,则需要自行跟踪。 如果需要调整arrays大小,则必须自己完成。

所有这些在一起,我很少使用数组,只是更经常使用ArrayList 。 但是,我经常使用List (或者只是CollectionSet )。 我最常使用的数组是当存储的项目是一个基元时,它将被插入并访问并用作基元。 如果拳击和拆箱都变得如此之快以至于变得微不足道,我可能会重新审视这个决定,但是以一种始终引用的forms处理某些东西,存储它会更方便。 (即’int’而不是’Integer’。)

很多项目只使用ArrayListHashMap或其他任何东西来处理它们的所有集合需求。 但是,让我对此提出一个警告。 无论何时在整个代码中创建类并使用它们,如果可能的话,请参考它们实现的接口,而不是用于实现它们的具体类。

例如,而不是:

 ArrayList insuranceClaims = new ArrayList(); 

做这个:

 List insuranceClaims = new ArrayList(); 

甚至:

 Collection insuranceClaims = new ArrayList(); 

如果您的代码的其余部分仅通过它实现的接口( ListCollection )知道它,那么如果您发现需要另一个实现,那么将其交换为另一个实现将变得更加容易。 我看到这种情况发生在一个月之前,当我需要换出一个普通的HashMap实现时,会按照我将它们放入的相同顺序将项目返回给我,当时需要迭代所有这些项目。 幸运的是,Jakarta Commons Collections中提供了这样的东西,我只用一行代码更改了A换B,因为两者都实现了Map。

这是一个过早未优化的案例:-)。 你永远不应该做某事,因为你认为它会更好/更快/让你更快乐。

ArrayList有额外的开销,如果你不需要ArrayList的额外function,那么使用ArrayList是浪费的。

还有一些你可以用List做的事情就是Arrays类,这意味着ArrayList提供的function比Arrays更少。 现在使用它们可能比使用ArrayList慢,但必须对其进行分析才能确定。

你永远不应该尝试更快地创造一些东西而不确定它开始的速度很慢……这意味着你应该继续使用ArrayList,直到你发现它们是一个问题并减慢程序的速度。 但是也应该有常识 – ArrayList有开销,开销很小但是累积。 在分析器中发现它并不容易,因为它只是在这里有点开销,并且在那里有一点开销。 所以常识会说,除非你需要ArrayList的function,否则你不应该使用它,除非你想要数千次削减(性能明智)。

对于内部代码,如果您发现需要从数组更改为ArrayList,则在大多数情况下([i]变为get(i),这将是99%的更改)。

如果您正在使用for-each外观(for(value:items){}),那么也没有代码可以更改。

另外,按照你所说的去做:

1)相同的访问速度,取决于您的环境。 例如,Android VM没有内联方法(据我所知,它只是一个直接的解释器),因此对它的访问速度要慢得多。 ArrayList上的其他操作可能会导致速度减慢,这取决于您正在做什么,无论VM是什么(对于直接arrays可能更快,再次您必须分析或检查源以确定)。

2)Wrappers增加了使用的内存量。

在分析某些内容之前,你不应该担心速度/内存,另一方面,除非你有充分的理由,否则你不应该选择你知道的更慢的选项。

性能不应该是您主要关注的问题。

尽可能使用List接口,根据实际需求选择具体实现( ArrayList用于随机访问, LinkedList用于结构修改,……)。

你应该关注表现。

使用数组, System.arraycopyjava.util.Arrays和其他低级东西来挤出每一滴性能。

好吧,不要总是盲目地使用一些不适合工作的东西。 始终使用列表开始,选择ArrayList作为您的实现。 这是一种更为面向对象的方法。 如果你不知道你特别需要一个数组,那么你会发现,从长远来看,不将自己绑定到List的特定实现会对你有好处。 让它先工作,稍后优化。