有人问到这个问题,顺便上网查资料深入了解了一下。以往问及什么时候用ArrayList什么时候用LinkedList,往往答案是,当大量随机检索数据时使用ArrayList,当频繁插入删除操作时使用LinkedList。按照数据结构来说,确实是LinkedList在插入删除操作时的复杂度要低于ArrayList。但在现实代码实现以及实际执行性能上,却不一定是这样。根据查阅的资料整理如下,欢迎讨论。


首先要了解两种List的不同应该先了解其代码实现。
ArrayList是通过索引访问的数组实现,而LinkedList使用过 链表原理实现。
ArrayList的get(i)不需要遍历可以直接通过索引获取数据,而LinkedList需要遍历,遍历到i索引位置时将当前位置数据返回。
网上有人贴了这样一段代码:
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedList list = new LinkedList();
for (int i =0;i<=1000000; i++) {
list.add(i);
}
long start = System.currentTimeMillis(); 
list.get(1);
long end = System.currentTimeMillis();
System.out.println(" time to traverse 1st element " + (end - start) );



start = System.currentTimeMillis(); 
list.get(999999);
end = System.currentTimeMillis();
System.out.println(" time take to traverse 999999th element " + (end - start) );

}

time to traverse 1st element 0
time to traverse 999999th element 0

他问既然LinkedList需要遍历读取数据,为什么我获取第一个数据和最后一个数据用的时间是一样的。
看一下LinkedList的get代码就应该明白了,遍历可能会从列表头部或末尾开始进行,取决于i在列表的前半部还是后半部分:
public Object get(int index) { 
//check the index is valid first .. code not shown here 
Entry e = header; //starting node 
//go forwards or backwards depending on which is closer 
if (index < size/2) { 
for (int i = 0; i <= index; i++) 
e = e.next; } 
else { 
for (int i = size; i > index; i--) 
e = e.previous; 

return e; 
}


同样在特定索引位置插入数据时,也是先遍历到那个位置再进行插入。这样很容易理解,当很大数据量时(比如1W),在LinkedList前部和后部进行删除插入操作,速度会很快,但是如果是在中部进行操作,测试结果就不那么乐观了,性能甚至不及ArrayList。


所以建议在数据量很大,同时存在链表头部以及尾部的频繁操作,并且很少执行中部数据操作时使用链表。其实这种情况也可以考虑使用ArrayDeque,因为链表在新增数据时会创建额外对象,记录上一node和下一个node的信息,会占用额外空间,而ArrayDeque则不会增加额外空间,不会增加GC工作。其他情况在ArrayList初始化大小设置合理时使用ArrayList能获得更好性能。


知道LinkedList的应用场景,再说说如何正确使用LinkedList。
首先是遍历,遍历LinkedList必须使用iterator不能使用for循环,因为每次for循环体内通过get(i)取得某一元素时都需要对list重新进行遍历,性能消耗极大。
另外不要试图使用indexOf等返回元素索引,并利用其进行遍历,例如下面的代码:
final int startPos = lst.indexOf( first ) + 1; //使用indexlOf对list进行了遍历,当结果为空时会遍历整个列表。
final ListIterator<String> iter = lst.listIterator( startPos ); //如果startPos的元素在列表前半部,那这两行代码相当于平均要遍历了列表1.25的长度,因为 listIterator( startPos )也需要从头遍历,当到达指定元素后开始循环如下操作。
while ( iter.hasNext() ) { 
if ( iter.next().length() == 5 ) 
iter.remove(); 
}




以上总结,网上的讨论很激烈,持有各自意见,以上为我的总结。有问题可以给我指出,谢谢。补充:以上就是关于ArrayList和LinkedList的差别。你需要一个不同步的基于索引的数据访问时,请尽量使用ArrayList。ArrayList很快,也很容易使用。但是要记得要给定一个合适的初始大小,尽可能的减少更改数组的大小。