`
shilimin
  • 浏览: 13789 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

jdk5的foreach语法糖带来了什么

    博客分类:
  • java
阅读更多

文章分析了下面这两种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接口是基于链表特性的,所以还是可用的,毕竟链表结构决定了它不是干这种活儿的。

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

1
4
分享到:
评论
2 楼 shilimin 2012-08-15  
arong 写道
学习了,做1000个左右的循环应该没啥区别吧。

量小时且单独执行确实体现不出来差别,但到线上上来并发后量就大了,而且对于有强迫症的程序员来说自然是能省则省了
1 楼 arong 2012-08-15  
学习了,做1000个左右的循环应该没啥区别吧。

相关推荐

    jdk5.zip

    增强的for循环(也称为foreach循环)是JDK 5中的一个语法糖,它简化了遍历数组和集合的操作。使用增强的for循环,可以无需知道索引即可遍历元素,使代码更简洁,更易于理解。 JDK 5还引入了可变参数(Varargs)功能...

    jdk5_64.zip

    这种语法糖极大地简化了处理不定数量参数的方法定义,如打印数组元素的util.println方法。 五、增强的for循环(For-Each Loop) 增强的for循环,也称为foreach循环,简化了遍历集合或数组的操作。例如:`for (Type...

    jdk5 64位exe文件.zip

    也称为foreach循环,这是一个简洁的语法糖,用于遍历集合、数组等可迭代对象,简化了迭代操作,使得代码更加简洁易读。 5. **类型推断(Type Inference)** 在Java 5中,编译器可以根据上下文推断匿名内部类和...

    Javajdk5学习笔记

    4. **变量声明的增强**:JDK 5允许在for循环中直接初始化和声明变量,如`for (String s : array) {...}`,这种语法被称为foreach循环或增强for循环。 5. **类型推断(Type Inference)**:在使用匿名内部类和泛型时...

    JDK 5中文文档PDF文档JDK 5中文文档PDF文档

    Java Development Kit (JDK) 5是Java编程语言的一个重要版本,由Sun Microsystems(后被Oracle公司收购)在2004年推出。这个版本引入了许多创新特性,极大地提升了开发效率和程序性能。JDK 5中文文档是针对这一版本...

    JDK1.8手册,中文

    JDK 1.8引入了Lambda表达式,这是一种简洁的函数式编程语法,可以用于表示无状态、无副作用的函数。Lambda表达式允许将匿名函数作为方法参数传递,或者用作方法返回值。例如,`Runnable r = () -&gt; System.out....

    java入门经典JDK5

    在JDK5中,还引入了增强的for循环(foreach loop),也称为迭代器简化。这种语法简化了遍历集合、数组等数据结构的操作,使得代码更加简洁易读。 最后,JDK5对异常处理进行了优化,添加了可检查异常的链式处理。当...

    (官方最新)真正支持jdk5的jad158g

    4. 增强的for循环(Foreach Loop):JDK 5引入的增强for循环使得遍历数组和集合更加简洁。Jad158g需要能够正确还原这种循环结构。 5. 注解(Annotations):注解是元数据的一种形式,可以为编译器、JVM或者工具提供...

    jdk1.5(jdk-1_5_0_08-windows-i586-p.exe)

    JDK 1.5,也被称为Java 5.0,是Oracle公司发布的一个重要Java开发工具包,它为Java编程语言带来了许多显著的改进和新特性。这个版本的JDK在2004年9月30日正式推出,其安装文件名为"jdk-1_5_0_08-windows-i586-p.exe...

    Jdk_5_CN.zip_jdk

    JDK 5是Java的一个重要版本,引入了许多新特性,如自动装箱/拆箱、枚举类型、泛型、可变参数、增强的for循环(foreach)等,这些特性极大地提高了代码的清晰度和可读性,也增强了Java的类型安全。 **7. CHM文件** ...

    java-JDK1.7.zip java-JDK1.7.zip

    2. **try-with-resources**:这是一个语法糖,使得资源管理更加简洁和安全。在try语句块中,它可以自动关闭实现了AutoCloseable接口的资源,避免了手动关闭时可能产生的资源泄露。 3. **多线程并行流**:Java 7引入...

    jdk1.6好用的jdk工具

    在JDK 1.6中,javac支持了更多的语法特性,如foreach循环、自动装箱/拆箱、可变参数等。 3. **JVM优化**:JDK 1.6对JVM进行了多方面的优化,包括更高效的垃圾回收机制、改进的类加载器以及对动态语言的支持等,这...

    jdk-1_5_0-windows

    在安装JDK 1.5.0的Windows版本时,用户需要下载名为`jdk-1_5_0-windows-i586%281%29.exe`的安装文件,根据安装向导完成安装过程,之后就可以在Windows环境下开发和运行Java程序了。注意,这个版本可能不再受到官方...

    jdk1.8中文api

    9. **双括号初始化**:这是一种快速创建匿名内部类的语法糖,常用于创建简单的工具类或配置类实例。 10. **类型推断的改进**:JDK 1.8增强了类型推断能力,编译器能更好地推断出局部变量的类型,使得代码更简洁。 ...

    JDK1.4.2-JDK1.6-JDK1.7-JDK1.8 中文帮助文档

    3. **增强的for循环(foreach)**:引入了简洁的语法来遍历集合和其他迭代器支持的数据结构。 4. **动态代理**:允许在运行时创建实现了指定接口的代理类,用于实现AOP(面向切面编程)或动态服务。 JDK1.6是另一...

    JDK帮助文档(jdk6,8,9,10,11)

    - **增强的for循环(foreach)**:引入了增强的for循环语法,简化了遍历数组和集合的操作。 - **Swing改进**:提供了新的布局管理器,如BoxLayout,以及对Swing组件的性能优化。 - **动态代理**:支持创建接口的...

    jdk宝典

    5. 可变参数(varargs):函数可以接受一个可变数量的参数,语法上表现为"Type... args",在内部会被转换为数组。 6. 注解(Annotation):注解是一种元数据,可以为编译器或JVM提供信息。例如,@Override表示方法...

    最新版jdk 8【百度网盘】

    5. **Optional类**:为了解决null值问题,JDK 8引入了Optional类,它可以帮助避免空指针异常,让代码更加清晰和安全。 6. **Date和Time API的改进**:JDK 8对日期和时间API进行了重大改革,引入了java.time包,包含...

    jdk-1_5_0_22-linux-i586.rar_5.0版本_jdk_jdk-1_5_0_22_lakee6q_linux

    5. **增强的for循环(foreach)**:也被称为“foreach”循环,是Java 5引入的一种简化迭代集合元素的新语法。它可以更简洁地遍历数组和集合,而无需手动处理索引。 6. **静态导入**:静态导入允许开发者将一个类的...

    JDK1.5版本免费下载

    5. **类型推断(Type Inference)**:在使用匿名内部类和局部变量时,编译器可以根据上下文推断出变量的类型,减少了冗余的类型声明。 6. **可变参数(Varargs)**:允许方法接受可变数量的参数,语法上类似于数组...

Global site tag (gtag.js) - Google Analytics