jdk5的foreach语法糖带来了什么

文章分析了下面这两种for循环的写法

for (int i = 0; i < list.size(); i++) {
	list.get(i);
}
for (String string : list) {
	;
}

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();
	}
}

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看下会发现程序一直在执行

LinkedList.get

也就是代码里的

list.get(i);

"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

这说明大数据量的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
  public void testArrayListFor();
    flags: ACC_PUBLIC
    Code:
      stack=6, locals=8, args_size=1
         0: new           #2                  // class java/util/ArrayList
         3: dup           
         4: invokespecial #3                  // Method java/util/ArrayList."":()V
         7: astore_1      
         8: iconst_0      
         9: istore_2      
        10: iload_2       
        11: ldc           #4                  // int 10000000
        13: if_icmpge     31
        16: aload_1       
        17: ldc           #5                  // String 1
        19: invokeinterface #6,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        24: pop           
        25: iinc          2, 1
        28: goto          10
        31: invokestatic  #7                  // Method java/lang/System.nanoTime:()J
        34: lstore_2      
        35: iconst_0      
        36: istore        4
        38: iload         4
        40: aload_1       
        41: invokeinterface #8,  1            // InterfaceMethod java/util/List.size:()I
        46: if_icmpge     64
        49: aload_1       
        50: iload         4
        52: invokeinterface #9,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
        57: pop           
        58: iinc          4, 1
        61: goto          38
        64: invokestatic  #7                  // Method java/lang/System.nanoTime:()J
        67: lstore        4
        69: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
        72: new           #11                 // class java/lang/StringBuilder
        75: dup           
        76: invokespecial #12                 // Method java/lang/StringBuilder."":()V
        79: ldc           #13                 // String for def:
        81: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        84: lload         4
        86: lload_2       
        87: lsub          
        88: invokevirtual #15                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
        91: invokevirtual #16                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        94: invokevirtual #17                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        97: invokestatic  #7                  // Method java/lang/System.nanoTime:()J
       100: lstore_2      
       101: aload_1       
       102: invokeinterface #18,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
       107: astore        6
       109: aload         6
       111: invokeinterface #19,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
       116: ifeq          134
       119: aload         6
       121: invokeinterface #20,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
       126: checkcast     #21                 // class java/lang/String
       129: astore        7
       131: goto          109
       134: invokestatic  #7                  // Method java/lang/System.nanoTime:()J
       137: lstore        4
       139: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
       142: new           #11                 // class java/lang/StringBuilder
       145: dup           
       146: invokespecial #12                 // Method java/lang/StringBuilder."":()V
       149: ldc           #22                 // String foreach:
       151: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
       154: lload         4
       156: lload_2       
       157: lsub          
       158: invokevirtual #15                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
       161: invokevirtual #16                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
       164: invokevirtual #17                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       167: return        

  public void testLinkedListFor();
    flags: ACC_PUBLIC
    Code:
      stack=6, locals=8, args_size=1
         0: new           #23                 // class java/util/LinkedList
         3: dup           
         4: invokespecial #24                 // Method java/util/LinkedList."":()V
         7: astore_1      
         8: iconst_0      
         9: istore_2      
        10: iload_2       
        11: ldc           #4                  // int 10000000
        13: if_icmpge     31
        16: aload_1       
        17: ldc           #5                  // String 1
        19: invokeinterface #6,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        24: pop           
        25: iinc          2, 1
        28: goto          10
        31: invokestatic  #7                  // Method java/lang/System.nanoTime:()J
        34: lstore_2      
        35: iconst_0      
        36: istore        4
        38: iload         4
        40: aload_1       
        41: invokeinterface #8,  1            // InterfaceMethod java/util/List.size:()I
        46: if_icmpge     55
        49: iinc          4, 1
        52: goto          38
        55: invokestatic  #7                  // Method java/lang/System.nanoTime:()J
        58: lstore        4
        60: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
        63: new           #11                 // class java/lang/StringBuilder
        66: dup           
        67: invokespecial #12                 // Method java/lang/StringBuilder."":()V
        70: ldc           #25                 // String fordef:
        72: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        75: lload         4
        77: lload_2       
        78: lsub          
        79: invokevirtual #15                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
        82: invokevirtual #16                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        85: invokevirtual #17                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        88: invokestatic  #7                  // Method java/lang/System.nanoTime:()J
        91: lstore_2      
        92: aload_1       
        93: invokeinterface #18,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
        98: astore        6
       100: aload         6
       102: invokeinterface #19,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
       107: ifeq          125
       110: aload         6
       112: invokeinterface #20,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
       117: checkcast     #21                 // class java/lang/String
       120: astore        7
       122: goto          100
       125: invokestatic  #7                  // Method java/lang/System.nanoTime:()J
       128: lstore        4
       130: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
       133: new           #11                 // class java/lang/StringBuilder
       136: dup           
       137: invokespecial #12                 // Method java/lang/StringBuilder."":()V
       140: ldc           #22                 // String foreach:
       142: invokevirtual #14                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
       145: lload         4
       147: lload_2       
       148: lsub          
       149: invokevirtual #15                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
       152: invokevirtual #16                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
       155: invokevirtual #17                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       158: return

3、结论
反编辑结果会发现foreach使用Iterator接口实现的,普通的循环直接使用List接口的get,这样就好理解了。
ArrayList底层是数组,通过下标访问自然是异常的快;通过Iterator接口则需要List.iterator:()、Iterator.hasNext:()和Iterator.next:()虽然最后取数据可是通过数组下标,但一连串的计算占用了一定时间,所以比起普通循环会慢上一些。
LinkedList是链表,用get就悲剧了,越往后越慢,取第10条数据还要把前9条数据溜一个遍(插入删除较多的、数据量较小的还是可用的),例子中1千万的数据量它肯定是玩不转的;LinkedList实现的Iterator接口是基于链表特性的,所以还是可用的,毕竟链表结构决定了它不是干这种活儿的。

编辑器弄不好了,原文地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值