- 浏览: 13789 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
shilimin:
arong 写道学习了,做1000个左右的循环应该没啥区别吧。 ...
jdk5的foreach语法糖带来了什么 -
arong:
学习了,做1000个左右的循环应该没啥区别吧。
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接口是基于链表特性的,所以还是可用的,毕竟链表结构决定了它不是干这种活儿的。
编辑器弄不好了,原文地址
评论
量小时且单独执行确实体现不出来差别,但到线上上来并发后量就大了,而且对于有强迫症的程序员来说自然是能省则省了
相关推荐
增强的for循环(也称为foreach循环)是JDK 5中的一个语法糖,它简化了遍历数组和集合的操作。使用增强的for循环,可以无需知道索引即可遍历元素,使代码更简洁,更易于理解。 JDK 5还引入了可变参数(Varargs)功能...
这种语法糖极大地简化了处理不定数量参数的方法定义,如打印数组元素的util.println方法。 五、增强的for循环(For-Each Loop) 增强的for循环,也称为foreach循环,简化了遍历集合或数组的操作。例如:`for (Type...
也称为foreach循环,这是一个简洁的语法糖,用于遍历集合、数组等可迭代对象,简化了迭代操作,使得代码更加简洁易读。 5. **类型推断(Type Inference)** 在Java 5中,编译器可以根据上下文推断匿名内部类和...
4. **变量声明的增强**:JDK 5允许在for循环中直接初始化和声明变量,如`for (String s : array) {...}`,这种语法被称为foreach循环或增强for循环。 5. **类型推断(Type Inference)**:在使用匿名内部类和泛型时...
Java Development Kit (JDK) 5是Java编程语言的一个重要版本,由Sun Microsystems(后被Oracle公司收购)在2004年推出。这个版本引入了许多创新特性,极大地提升了开发效率和程序性能。JDK 5中文文档是针对这一版本...
JDK 1.8引入了Lambda表达式,这是一种简洁的函数式编程语法,可以用于表示无状态、无副作用的函数。Lambda表达式允许将匿名函数作为方法参数传递,或者用作方法返回值。例如,`Runnable r = () -> System.out....
在JDK5中,还引入了增强的for循环(foreach loop),也称为迭代器简化。这种语法简化了遍历集合、数组等数据结构的操作,使得代码更加简洁易读。 最后,JDK5对异常处理进行了优化,添加了可检查异常的链式处理。当...
4. 增强的for循环(Foreach Loop):JDK 5引入的增强for循环使得遍历数组和集合更加简洁。Jad158g需要能够正确还原这种循环结构。 5. 注解(Annotations):注解是元数据的一种形式,可以为编译器、JVM或者工具提供...
JDK 1.5,也被称为Java 5.0,是Oracle公司发布的一个重要Java开发工具包,它为Java编程语言带来了许多显著的改进和新特性。这个版本的JDK在2004年9月30日正式推出,其安装文件名为"jdk-1_5_0_08-windows-i586-p.exe...
JDK 5是Java的一个重要版本,引入了许多新特性,如自动装箱/拆箱、枚举类型、泛型、可变参数、增强的for循环(foreach)等,这些特性极大地提高了代码的清晰度和可读性,也增强了Java的类型安全。 **7. CHM文件** ...
2. **try-with-resources**:这是一个语法糖,使得资源管理更加简洁和安全。在try语句块中,它可以自动关闭实现了AutoCloseable接口的资源,避免了手动关闭时可能产生的资源泄露。 3. **多线程并行流**:Java 7引入...
在JDK 1.6中,javac支持了更多的语法特性,如foreach循环、自动装箱/拆箱、可变参数等。 3. **JVM优化**:JDK 1.6对JVM进行了多方面的优化,包括更高效的垃圾回收机制、改进的类加载器以及对动态语言的支持等,这...
在安装JDK 1.5.0的Windows版本时,用户需要下载名为`jdk-1_5_0-windows-i586%281%29.exe`的安装文件,根据安装向导完成安装过程,之后就可以在Windows环境下开发和运行Java程序了。注意,这个版本可能不再受到官方...
9. **双括号初始化**:这是一种快速创建匿名内部类的语法糖,常用于创建简单的工具类或配置类实例。 10. **类型推断的改进**:JDK 1.8增强了类型推断能力,编译器能更好地推断出局部变量的类型,使得代码更简洁。 ...
3. **增强的for循环(foreach)**:引入了简洁的语法来遍历集合和其他迭代器支持的数据结构。 4. **动态代理**:允许在运行时创建实现了指定接口的代理类,用于实现AOP(面向切面编程)或动态服务。 JDK1.6是另一...
- **增强的for循环(foreach)**:引入了增强的for循环语法,简化了遍历数组和集合的操作。 - **Swing改进**:提供了新的布局管理器,如BoxLayout,以及对Swing组件的性能优化。 - **动态代理**:支持创建接口的...
5. 可变参数(varargs):函数可以接受一个可变数量的参数,语法上表现为"Type... args",在内部会被转换为数组。 6. 注解(Annotation):注解是一种元数据,可以为编译器或JVM提供信息。例如,@Override表示方法...
5. **Optional类**:为了解决null值问题,JDK 8引入了Optional类,它可以帮助避免空指针异常,让代码更加清晰和安全。 6. **Date和Time API的改进**:JDK 8对日期和时间API进行了重大改革,引入了java.time包,包含...
5. **增强的for循环(foreach)**:也被称为“foreach”循环,是Java 5引入的一种简化迭代集合元素的新语法。它可以更简洁地遍历数组和集合,而无需手动处理索引。 6. **静态导入**:静态导入允许开发者将一个类的...
5. **类型推断(Type Inference)**:在使用匿名内部类和局部变量时,编译器可以根据上下文推断出变量的类型,减少了冗余的类型声明。 6. **可变参数(Varargs)**:允许方法接受可变数量的参数,语法上类似于数组...