TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
对ArrayList和LinkedList的两种for循环的写法
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
for (String string : list) {
;
}[/code]
1、执行看效率
选用了两种有代表性的List,分别是ArrayList和LinkedList
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class DealForTest {
public void testArrayListFor() {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10000000; i++) {
list.add("1");
}
long s = System.nanoTime();
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
long e = System.nanoTime();
System.out.println("for def:" + (e - s));
s = System.nanoTime();
for (String str : list) {
;
}
e = System.nanoTime();
System.out.println("foreach:" + (e - s));
}
public void testLinkedListFor() {
List<String> list = new LinkedList<String>();
for (int i = 0; i < 10000000; i++) {
list.add("1");
}
long s = System.nanoTime();
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
long e = System.nanoTime();
System.out.println("fordef:" + (e - s));
s = System.nanoTime();
for (String str : list) {
;
}
e = System.nanoTime();
System.out.println("foreach:" + (e - s));
}
public static void main(String[] args) {
DealForTest test = new DealForTest();
test.testArrayListFor();
}
}[/code]
testArrayListFor方法执行结果如下:
[root@li494-25 java]# java -Xms512m DealForTest
for def:216475470
foreach:220800083
[root@li494-25 java]# java -Xms512m DealForTest
for def:155585111
foreach:201191721
[root@li494-25 java]# java -Xms512m DealForTest
for def:171001760
foreach:199440627
[root@li494-25 java]# java -Xms512m DealForTest
for def:168588851
foreach:202388936
一共执行了4次,明显可以看出普通的for循环比foreach快了那么一点点
把test.testArrayListFor();改成test.testLinkedListFor();再执行
悲剧了,程序好像夯住了,我们用jstack看下会发现程序一直在执行
也就是代码里的
[blockquote]
"main" prio=10 tid=0xb6c05400 nid=0x3aed runnable [0xb6dee000]
java.lang.Thread.State: RUNNABLE
at java.util.LinkedList.node(LinkedList.java:569)
at java.util.LinkedList.get(LinkedList.java:475)
at DealForTest.testLinkedListFor(DealForTest.java:34)
at DealForTest.main(DealForTest.java:49)
"VM Thread" prio=10 tid=0xb6c7a800 nid=0x3aee runnable
[/blockquote]
这说明大数据量的LinkedList的get根本没法用,注释掉代码里的list.get(i);再次执行如果如下:
[root@li494-25 java]# java -Xms512m DealForTest
fordef:108696577
foreach:262918732
[root@li494-25 java]# java -Xms512m DealForTest
fordef:81297371
foreach:239272835
[root@li494-25 java]# java -Xms512m DealForTest
fordef:80040708
foreach:238010609
[root@li494-25 java]# java -Xms512m DealForTest
fordef:79126135
foreach:283810388
一共执行4次,普通循环没法用,foreach虽然没有ArrayList的foreach快,但至少也能用了
2、为什么会这样?ArrayList的foreach为什么会慢、LinkedList普通for循环在大数据量时为什么不可用,而foreach可用?
反编辑下看看
- 编辑命令稍微变化一下:javac -g DealForTest.java
- 再使用javap -v DealForTest
-
复制代码
3、结论
反编辑结果会发现foreach使用Iterator接口实现的,普通的循环直接使用List接口的get,这样就好理解了。 ArrayList底层是数组,通过下标访问自然是异常的快;通过Iterator接口则需要List.iterator:()、Iterator.hasNext:()和Iterator.next:()虽然最后取数据可是通过数组下标,但一连串的计算占用了一定时间,所以比起普通循环会慢上一些。
LinkedList是链表,用get就悲剧了,越往后越慢,取第10条数据还要把前9条数据溜一个遍(插入删除较多的、数据量较小的还是可用的),例子中1千万的数据量它肯定是玩不转的;LinkedList实现的Iterator接口是基于链表特性的,所以还是可用的,毕竟链表结构决定了它不是干这种活儿的。 |
|